Concurrency
Concurrency allows you to handle multiple tasks at once, which is crucial for improving efficiency and responsiveness in programs. Python provides various models for concurrency such as Threading, Mul
Concurrency Methods
Threading
Runs multiple threads in the same memory space.
I/O-bound tasks like network calls, file reading.
1. Lightweight 2. Simple syntax
1. Blocked by GIL 2. Not ideal for CPU-heavy tasks
GIL (Global Interpreter Lock)
A lock that prevents multiple threads from executing bytecodes simultaneously.
Restricts Python's multi-threading to one thread at a time.
1. Simplifies memory management
1. Limits CPU-bound multi-threading
Multiprocessing
Launches separate processes, each with its own memory space.
CPU-bound tasks such as data crunching, video rendering.
1. True parallelism 2. Bypasses GIL
1. Higher memory use 2. More overhead due to inter-process communication
AsyncIO
Cooperative multitasking using async
and await
.
Efficient for I/O-heavy operations like socket or web communication.
1. Scalable 2. Low memory footprint
1. Learning curve 2. Not for CPU-heavy tasks
ThreadPoolExecutor
High-level interface for threading via concurrent.futures
.
Parallelize simple I/O tasks.
1. Easy to use 2. Manages threads efficiently
1. GIL still applies
ProcessPoolExecutor
High-level interface for multiprocessing.
Parallelize CPU-heavy computations.
1. Simple API 2. Avoids GIL
1. Slower startup 2. High memory usage
Thread-safe Queue
Queue class from queue
module, useful for thread/process communication.
Sharing data between workers.
1. Safe and reliable data exchange
1. Slight overhead
aiohttp
Async HTTP client for asyncio-based applications.
High-performance async web scraping and APIs.
1. Built-in connection pooling 2. Easy coroutine integration
1. Async-only, requires different architecture
Comparison: AsyncIO vs Threading vs Multiprocessing
Best For
I/O-bound & high concurrency
I/O-bound tasks
CPU-bound heavy computation
Memory Usage
Low
Medium
High
GIL Affected?
No
Yes
No
Parallelism
Cooperative (non-blocking)
Pseudo-parallelism (blocked by GIL)
True parallelism
Complexity
Medium to High
Low
Medium
Code Samples
import threading
import time
def download_file(file_id):
print(f"Downloading file {file_id}...")
time.sleep(2)
print(f"Finished downloading file {file_id}")
threads = []
for i in range(3):
t = threading.Thread(target=download_file, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
# ===== Output ==========
"""
Downloading file 0...
Downloading file 1...
Downloading file 2...
Finished downloading file 0
Finished downloading file 1
Finished downloading file 2
"""
from concurrent.futures import ThreadPoolExecutor
def greet(name):
return f"Hello, {name}!"
names = ["Alice", "Bob", "Charlie"]
with ThreadPoolExecutor() as executor:
results = executor.map(greet, names)
for result in results:
print(result)
# output
"""
Hello, Alice!
Hello, Bob!
Hello, Charlie!
"""
Last updated