- Web scraping β fetching multiple pages concurrently
- Download managers β downloading multiple files at once
- GUI applications β keeping UI responsive
- Database operations β running multiple queries
- API calls β making multiple requests in parallel
- Background processing β tasks running in the background
Why Threads Matter
Threads are useful in many real-world applications. They help you do multiple things at once, making your programs faster and more responsive.
β‘ Think of it like a restaurant kitchen.
Without threads: One chef does everything β takes orders, cooks, cleans. Everything is slow.
With threads: Multiple chefs work simultaneously β one takes orders, another cooks, another cleans. Everything is fast and efficient!
Web Scraping
Fetch multiple web pages at the same time
Download Managers
Download multiple files in parallel
GUI Applications
Keep the user interface responsive
Database Operations
Run multiple queries concurrently
API Calls
Make multiple API requests at once
Background Processing
Run tasks in the background
π‘ Key concept: Threads are ideal for I/O-bound tasks where the program waits for external resources like network, disk, or user input.
When to Use Threads
# ============================================================
# WHEN TO USE THREADS
# ============================================================
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USE THREADS FOR: β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1. Network operations (web requests, API calls) β
β 2. File I/O (reading/writing files) β
β 3. Database queries β
β 4. User interface interactions β
β 5. Background tasks (logging, monitoring) β
β 6. Batch processing (multiple similar tasks) β
β β
β AVOID THREADS FOR: β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1. CPU-intensive calculations β
β 2. Heavy numerical processing β
β 3. Tasks that need true parallelism β
β 4. Work that doesn't involve waiting β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
Key point: Threads are best when your program spends time waiting for external resources.
Quick Check: What type of tasks are threads best for? (Answer: I/O-bound tasks that involve waiting)
Web Scraping
Fetching Multiple Pages Concurrently
Web scraping involves fetching data from websites. Without threads, you fetch one page at a time. With threads, you can fetch multiple pages simultaneously.
# ============================================================
# WEB SCRAPING WITH THREADS
# ============================================================
import threading
import time
import random
# ============================================================
# SIMULATED WEB SCRAPING
# ============================================================
def fetch_page(url):
"""Simulate fetching a web page"""
thread_name = threading.current_thread().name
print(f"[{thread_name}] Fetching: {url}")
# Simulate network delay
delay = random.uniform(0.5, 1.5)
time.sleep(delay)
# Simulate page content
content = f"Content from {url} (took {delay:.2f}s)"
print(f"[{thread_name}] Done: {url}")
return content
def scrape_pages(urls):
"""Scrape multiple pages using threads"""
threads = []
results = {}
def scrape_one(url):
results[url] = fetch_page(url)
# Create and start threads
for url in urls:
t = threading.Thread(target=scrape_one, args=(url,))
threads.append(t)
t.start()
# Wait for all threads
for t in threads:
t.join()
return results
print("=" * 60)
print("WEB SCRAPING WITH THREADS")
print("=" * 60)
# List of URLs to scrape
urls = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
"https://example.com/page4",
"https://example.com/page5"
]
print(f"Scraping {len(urls)} pages...")
# Scrape without threads (sequential)
print("\n1. SEQUENTIAL SCRAPING:")
start = time.time()
for url in urls:
fetch_page(url)
sequential_time = time.time() - start
print(f"Sequential time: {sequential_time:.2f}s")
# Scrape with threads (parallel)
print("\n2. PARALLEL SCRAPING:")
start = time.time()
results = scrape_pages(urls)
parallel_time = time.time() - start
print(f"Parallel time: {parallel_time:.2f}s")
print(f"\nSpeedup: {sequential_time/parallel_time:.2f}x")
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BENEFITS OF THREADED WEB SCRAPING: β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β’ Multiple pages fetched at the same time β
β β’ Total time = time of slowest page (not sum of all) β
β β’ Much faster for many pages β
β β’ Simple to implement with threads β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
Web scraping key points:
- Parallel fetching β multiple pages at once
- Speedup β total time = slowest page
- Simple β easy to implement
- Scalable β can handle many pages
Quick Check: Why is threading useful for web scraping? (Answer: It allows fetching multiple pages at the same time)
Download Managers
Downloading Multiple Files Simultaneously
# ============================================================
# DOWNLOAD MANAGER WITH THREADS
# ============================================================
import threading
import time
import random
import os
# ============================================================
# SIMULATED DOWNLOAD MANAGER
# ============================================================
class DownloadManager:
"""Download multiple files using threads"""
def __init__(self):
self.downloads = []
self.completed = 0
self.lock = threading.Lock()
def download_file(self, file_name, size_mb):
"""Simulate downloading a file"""
thread_name = threading.current_thread().name
print(f"[{thread_name}] Starting download: {file_name} ({size_mb}MB)")
self.downloads.append(file_name)
# Simulate download progress
for progress in range(0, 101, 20):
time.sleep(random.uniform(0.2, 0.5))
print(f"[{thread_name}] {file_name}: {progress}% complete")
# Thread-safe counter update
with self.lock:
self.completed += 1
print(f"[{thread_name}] Completed: {file_name}")
return file_name
def start_downloads(self, files):
"""Start multiple downloads in parallel"""
threads = []
start_time = time.time()
for file_name, size in files:
t = threading.Thread(
target=self.download_file,
args=(file_name, size),
name=f"Download-{file_name[:5]}"
)
threads.append(t)
t.start()
# Wait for all downloads
for t in threads:
t.join()
end_time = time.time()
print(f"\nAll downloads completed!")
print(f"Total files: {len(files)}")
print(f"Total time: {end_time - start_time:.2f}s")
print(f"Files: {', '.join(self.downloads)}")
print("=" * 60)
print("DOWNLOAD MANAGER WITH THREADS")
print("=" * 60)
# Files to download (name, size in MB)
files = [
("movie.mp4", 150),
("document.pdf", 5),
("music.mp3", 10),
("image.jpg", 3),
("game.exe", 500)
]
manager = DownloadManager()
manager.start_downloads(files)
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BENEFITS OF THREADED DOWNLOAD MANAGER: β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β’ Multiple files download simultaneously β
β β’ Total time = time of largest file (not sum of all) β
β β’ Progress tracking for each file β
β β’ User interface remains responsive β
β β’ Can pause/resume individual downloads β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
Download manager key points:
- Parallel downloads β multiple files at once
- Time savings β total time reduced
- Progress tracking β each file monitored
- Responsive β UI remains usable
Quick Check: How does a threaded download manager improve performance? (Answer: By downloading multiple files simultaneously)
GUI Applications
Keeping Your UI Responsive
# ============================================================
# GUI APPLICATIONS WITH THREADS
# ============================================================
import threading
import time
import tkinter as tk
# ============================================================
# SIMPLE GUI WITH BACKGROUND THREAD
# ============================================================
class ResponsiveGUI:
"""GUI application that stays responsive"""
def __init__(self):
self.root = tk.Tk()
self.root.title("Responsive GUI")
self.root.geometry("300x200")
# Status label
self.status = tk.Label(self.root, text="Ready", font=("Arial", 12))
self.status.pack(pady=20)
# Start button
self.start_btn = tk.Button(
self.root,
text="Start Task",
command=self.start_task,
font=("Arial", 12)
)
self.start_btn.pack(pady=10)
# Stop button
self.stop_btn = tk.Button(
self.root,
text="Stop",
command=self.stop_task,
font=("Arial", 12)
)
self.stop_btn.pack(pady=10)
self.task_running = False
def start_task(self):
"""Start a background task"""
if self.task_running:
return
self.task_running = True
self.status.config(text="Task running...")
self.start_btn.config(state=tk.DISABLED)
# Start background thread
t = threading.Thread(target=self.long_task)
t.daemon = True
t.start()
def long_task(self):
"""Simulate a long-running task"""
for i in range(1, 11):
if not self.task_running:
break
# Update UI from main thread
self.root.after(0, self.update_status, i)
time.sleep(0.5)
self.root.after(0, self.task_complete)
def update_status(self, progress):
"""Update status label"""
self.status.config(text=f"Task: {progress*10}% complete")
def task_complete(self):
"""Handle task completion"""
self.task_running = False
self.status.config(text="Task complete!")
self.start_btn.config(state=tk.NORMAL)
def stop_task(self):
"""Stop the running task"""
self.task_running = False
self.status.config(text="Task stopped")
self.start_btn.config(state=tk.NORMAL)
def run(self):
self.root.mainloop()
# ============================================================
# RUN THE GUI
# ============================================================
print("=" * 60)
print("GUI APPLICATIONS WITH THREADS")
print("=" * 60)
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BENEFITS OF THREADS IN GUI APPLICATIONS: β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β’ UI stays responsive during long tasks β
β β’ User can interact with the interface β
β β’ No "Not Responding" messages β
β β’ Can cancel/stop tasks β
β β’ Better user experience β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
print("""
NOTE: To run the GUI example, uncomment the code and run it locally.
This demonstrates how threads keep the UI responsive.
""")
# Uncomment to run the GUI:
# app = ResponsiveGUI()
# app.run()
GUI key points:
- Responsive UI β no freezing
- Background tasks β run in separate threads
- User interaction β can cancel tasks
- Better experience β professional feel
Quick Check: Why use threads in GUI applications? (Answer: To keep the UI responsive during long operations)
Database Operations
Running Multiple Queries Concurrently
# ============================================================
# DATABASE OPERATIONS WITH THREADS
# ============================================================
import threading
import time
import random
# ============================================================
# SIMULATED DATABASE OPERATIONS
# ============================================================
class DatabaseThread:
"""Simulate database operations with threads"""
def __init__(self):
self.results = {}
self.lock = threading.Lock()
def run_query(self, query_id, query_type, delay):
"""Simulate a database query"""
thread_name = threading.current_thread().name
print(f"[{thread_name}] Running query {query_id}: {query_type}")
time.sleep(delay)
result = f"Result from query {query_id} ({query_type})"
with self.lock:
self.results[query_id] = result
print(f"[{thread_name}] Query {query_id} completed")
return result
def run_queries(self, queries):
"""Run multiple queries in parallel"""
threads = []
for query_id, query_type, delay in queries:
t = threading.Thread(
target=self.run_query,
args=(query_id, query_type, delay),
name=f"DB-{query_id}"
)
threads.append(t)
t.start()
for t in threads:
t.join()
return self.results
print("=" * 60)
print("DATABASE OPERATIONS WITH THREADS")
print("=" * 60)
db = DatabaseThread()
# Simulated queries: (id, type, delay in seconds)
queries = [
(1, "SELECT * FROM users", 0.5),
(2, "SELECT * FROM orders", 0.8),
(3, "SELECT * FROM products", 0.3),
(4, "SELECT * FROM customers", 0.6),
(5, "SELECT * FROM inventory", 0.4)
]
print("Running 5 database queries in parallel...")
start = time.time()
# Run queries in parallel
results = db.run_queries(queries)
total_time = time.time() - start
print(f"\nAll queries completed!")
print(f"Total time: {total_time:.2f}s")
print(f"Queries: {len(results)}")
for query_id, result in results.items():
print(f" Query {query_id}: {result}")
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BENEFITS OF THREADED DATABASE OPERATIONS: β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β’ Multiple queries run in parallel β
β β’ Total time = time of slowest query (not sum of all) β
β β’ Database connections can be pooled β
β β’ Better resource utilization β
β β’ Faster overall execution β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
Database operations key points:
- Parallel queries β multiple queries at once
- Time savings β total time reduced
- Connection pooling β efficient resource use
- Faster reports β quicker data access
Quick Check: Why use threads for database queries? (Answer: To run multiple queries in parallel and reduce total time)
API Calls
Making Multiple API Requests in Parallel
# ============================================================
# API CALLS WITH THREADS
# ============================================================
import threading
import time
import random
import json
# ============================================================
# SIMULATED API CALLS
# ============================================================
def make_api_call(endpoint, data):
"""Simulate making an API call"""
thread_name = threading.current_thread().name
print(f"[{thread_name}] Calling: {endpoint}")
# Simulate network delay
delay = random.uniform(0.3, 1.0)
time.sleep(delay)
# Simulate response
response = {
"endpoint": endpoint,
"data": data,
"status": "success",
"timestamp": time.time(),
"delay": delay
}
print(f"[{thread_name}] Response received from {endpoint}")
return response
def call_apis(api_list):
"""Call multiple APIs in parallel"""
threads = []
results = {}
def call_one(endpoint, data):
results[endpoint] = make_api_call(endpoint, data)
for endpoint, data in api_list:
t = threading.Thread(
target=call_one,
args=(endpoint, data),
name=f"API-{endpoint[:10]}"
)
threads.append(t)
t.start()
for t in threads:
t.join()
return results
print("=" * 60)
print("API CALLS WITH THREADS")
print("=" * 60)
# APIs to call: (endpoint, data)
apis = [
("users/get", {"user_id": 1}),
("orders/list", {"limit": 10}),
("products/search", {"query": "laptop"}),
("customers/profile", {"customer_id": 5}),
("inventory/check", {"product_id": 100})
]
print("Calling 5 APIs in parallel...")
start = time.time()
# Call APIs in parallel
results = call_apis(apis)
total_time = time.time() - start
print(f"\nAll APIs called!")
print(f"Total time: {total_time:.2f}s")
print(f"APIs: {len(results)}")
for endpoint, response in results.items():
print(f" {endpoint}: {response['status']} (took {response['delay']:.2f}s)")
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BENEFITS OF THREADED API CALLS: β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β’ Multiple APIs called simultaneously β
β β’ Total time = time of slowest API (not sum of all) β
β β’ Better user experience (faster responses) β
β β’ Can aggregate data from multiple sources β
β β’ Efficient resource utilization β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
API calls key points:
- Parallel requests β multiple APIs at once
- Faster responses β total time reduced
- Data aggregation β combine results
- Better UX β faster loading times
Quick Check: Why use threads for API calls? (Answer: To make multiple API requests in parallel and reduce total time)
Background Processing
Running Tasks in the Background
# ============================================================
# BACKGROUND PROCESSING WITH THREADS
# ============================================================
import threading
import time
import queue
# ============================================================
# BACKGROUND TASK QUEUE
# ============================================================
class BackgroundProcessor:
"""Process tasks in the background"""
def __init__(self):
self.task_queue = queue.Queue()
self.results = []
self.running = True
self.worker_thread = None
def start(self):
"""Start the background worker"""
self.worker_thread = threading.Thread(target=self._worker)
self.worker_thread.daemon = True
self.worker_thread.start()
print("Background worker started")
def stop(self):
"""Stop the background worker"""
self.running = False
if self.worker_thread:
self.worker_thread.join(timeout=1)
print("Background worker stopped")
def add_task(self, task_name, task_func, *args):
"""Add a task to the queue"""
self.task_queue.put((task_name, task_func, args))
print(f"Task added: {task_name}")
def _worker(self):
"""Background worker thread"""
while self.running:
try:
# Get task from queue (with timeout)
task_name, task_func, args = self.task_queue.get(timeout=1)
print(f"Processing: {task_name}")
result = task_func(*args)
self.results.append((task_name, result))
print(f"Completed: {task_name}")
self.task_queue.task_done()
except queue.Empty:
# No tasks, continue
continue
except Exception as e:
print(f"Error processing task: {e}")
def get_results(self):
"""Get all results"""
return self.results
# ============================================================
# SAMPLE TASKS
# ============================================================
def process_file(file_name):
"""Simulate processing a file"""
time.sleep(0.5)
return f"Processed {file_name}"
def send_email(recipient, subject):
"""Simulate sending an email"""
time.sleep(0.3)
return f"Email sent to {recipient}: {subject}"
def generate_report(report_type):
"""Simulate generating a report"""
time.sleep(0.8)
return f"Generated {report_type} report"
print("=" * 60)
print("BACKGROUND PROCESSING WITH THREADS")
print("=" * 60)
# Create background processor
processor = BackgroundProcessor()
processor.start()
# Add tasks
print("\nAdding tasks to background queue...")
processor.add_task("File A", process_file, "data.csv")
processor.add_task("File B", process_file, "report.pdf")
processor.add_task("Email", send_email, "admin@example.com", "Daily Report")
processor.add_task("Report", generate_report, "Sales")
# Wait for tasks to complete
print("\nWaiting for tasks to complete...")
time.sleep(4)
# Stop the processor
processor.stop()
# Get results
print("\nResults:")
for task_name, result in processor.get_results():
print(f" {task_name}: {result}")
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BENEFITS OF BACKGROUND PROCESSING: β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β’ Tasks run in the background β
β β’ Main program continues working β
β β’ Tasks are queued and processed asynchronously β
β β’ No blocking of main thread β
β β’ Can handle multiple tasks efficiently β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
Background processing key points:
- Asynchronous β tasks run in background
- Queued β tasks are processed in order
- Non-blocking β main thread continues
- Scalable β can handle many tasks
Quick Check: What is background processing used for? (Answer: Running tasks without blocking the main program)
Real-World Example
Complete Real-World Application
# ============================================================
# COMPLETE REAL-WORLD APPLICATION
# ============================================================
import threading
import time
import random
import json
class DataProcessor:
"""Complete data processing application with threads"""
def __init__(self):
self.tasks = []
self.results = []
self.lock = threading.Lock()
# ============================================================
# TASK FUNCTIONS
# ============================================================
def fetch_data(self, source):
"""Fetch data from a source"""
time.sleep(random.uniform(0.3, 0.7))
return f"Data from {source}"
def process_data(self, data):
"""Process the fetched data"""
time.sleep(random.uniform(0.2, 0.5))
return f"Processed: {data}"
def save_data(self, data):
"""Save processed data"""
time.sleep(random.uniform(0.1, 0.3))
return f"Saved: {data}"
# ============================================================
# WORKFLOW FUNCTIONS
# ============================================================
def run_workflow(self, source):
"""Complete workflow with threads"""
print(f"\nProcessing source: {source}")
# Step 1: Fetch data
data = self.fetch_data(source)
print(f" Fetched from {source}")
# Step 2: Process data
processed = self.process_data(data)
print(f" Processed data")
# Step 3: Save data
saved = self.save_data(processed)
print(f" Saved data")
return saved
def run_parallel_workflows(self, sources):
"""Run multiple workflows in parallel"""
threads = []
results = {}
def run_one(source):
results[source] = self.run_workflow(source)
print("Starting parallel workflows...")
start = time.time()
for source in sources:
t = threading.Thread(target=run_one, args=(source,))
threads.append(t)
t.start()
for t in threads:
t.join()
end = time.time()
print(f"\nAll workflows completed in {end - start:.2f}s")
return results
# ============================================================
# DEMONSTRATION
# ============================================================
print("=" * 60)
print("COMPLETE REAL-WORLD APPLICATION")
print("=" * 60)
processor = DataProcessor()
# Sources to process
sources = ["Database", "API", "File System", "Web Service", "Cache"]
print("Processing 5 sources...\n")
# Run parallel workflows
results = processor.run_parallel_workflows(sources)
print("\nResults:")
for source, result in results.items():
print(f" {source}: {result}")
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WHAT THIS APPLICATION DEMONSTRATES: β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1. Real-world data processing pipeline β
β 2. Multiple sources processed in parallel β
β 3. Each workflow: Fetch β Process β Save β
β 4. Threads for each source β
β 5. Results collected and displayed β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
Real-world example key points:
- Complete workflow β fetch, process, save
- Parallel processing β multiple sources
- Thread safety β locks for shared data
- Real-world β practical application
Quick Check: What makes this a real-world example? (Answer: It shows a complete data processing pipeline with parallel workflows)
Best Practices
Best Practices for Using Threads
# ============================================================
# BEST PRACTICES FOR THREADS
# ============================================================
print("1. USE THREADS FOR I/O-BOUND TASKS")
print(" - Network operations, file I/O, database queries")
print(" - Not for CPU-intensive work")
print("\n2. USE THREAD POOLS FOR MANY TASKS")
print(" - from concurrent.futures import ThreadPoolExecutor")
print(" - Reuses threads efficiently")
print("\n3. USE QUEUES FOR THREAD COMMUNICATION")
print(" - from queue import Queue")
print(" - Thread-safe communication")
print("\n4. USE LOCKS FOR SHARED DATA")
print(" - from threading import Lock")
print(" - Prevent race conditions")
print("\n5. HANDLE EXCEPTIONS IN THREADS")
print(" - Exceptions in threads don't propagate to main")
print(" - Use try/except inside thread functions")
print("\n6. LIMIT THE NUMBER OF THREADS")
print(" - Too many threads = performance degradation")
print(" - Use pools to manage limits")
print("\n7. USE DAEMON THREADS CAREFULLY")
print(" - Use for background tasks")
print(" - Don't use for critical work")
print("\n8. ALWAYS JOIN THREADS")
print(" - Ensure threads complete before program exits")
print(" - Prevents resource leaks")
Best practices summary:
- Use for I/O β not CPU work
- Use pools β manage many threads
- Use queues β thread-safe communication
- Use locks β prevent race conditions
Quick Check: What should you use for thread-safe communication? (Answer: Queue)
Try It Yourself
Experiment with different uses of threads in the editor below.
USES OF THREADS - PRACTICE
========================================
1. WEB SCRAPING SIMULATION
----------------------------------------
Scraping 3 pages in parallel...
Page 1: Started
Page 2: Started
Page 3: Started
Page 3: Completed
Page 1: Completed
Page 2: Completed
2. DOWNLOAD MANAGER SIMULATION
----------------------------------------
Downloading 3 files in parallel...
movie.mp4: Starting download (150MB)
document.pdf: Starting download (5MB)
music.mp3: Starting download (10MB)
music.mp3: Download complete!
document.pdf: Download complete!
movie.mp4: Download complete!
3. USES OF THREADS SUMMARY
----------------------------------------
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USE CASE β BENEFIT β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Web Scraping β Fetch multiple pages in parallel β
β Download Manager β Download multiple files at once β
β GUI Applications β Keep UI responsive β
β Database Queries β Run multiple queries concurrently β
β API Calls β Make multiple requests in parallel β
β Background Tasks β Process tasks without blocking β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
4. RECOMMENDATIONS
----------------------------------------
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Scenario β Recommended Approach β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Web scraping many pages β Use ThreadPoolExecutor β
β Downloading files β Use threading with progress trackingβ
β Keeping UI responsive β Use threading for background tasks β
β Multiple DB queries β Use threading with connection pools β
β Many API calls β Use ThreadPoolExecutor β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Threads make many real-world applications faster and more responsive!
You've Got It!
You now understand the practical uses of threads in Python. You know how to apply threading to web scraping, download managers, GUI applications, and more.
Quick Quiz
Test what you've learned:
Frequently Asked Questions
What is the most common use of threads?
Can I use threads for CPU-intensive tasks?
What is a common interview question about thread uses?
What is the difference between threads and asyncio?
How many threads should I create?
Where to Go From Here
Now that you understand the uses of threads, check out these related topics:
Creating Threads
Deep dive into creating and managing threads.
Learn More βSingle Tasking
Learn about single-threaded execution.
Learn More βMulti Tasking
Learn about concurrent execution.
Learn More β