Python Multitasking
- General term for performing multiple tasks simultaneously.
- Can be achieved through threading, multiprocessing, or asynchronous programming.
CPU Bound | Multi Processing |
I/O Bound, Fast I/O, Limited Number of Connections | Multi Threading |
I/O Bound, Slow I/O, Many connections | Asyncio |
if io_bound:
if io_very_slow:
print("Use Asyncio")
else:
print("Use Threads")
else:
print("Multi Processing")
Multithreading (Thread-based concurrency)
- Uses multiple threads within the same process.
- Threads share the same memory space.
- Python’s Global Interpreter Lock (GIL) restricts true parallel execution of threads.
- Best for I/O-bound tasks (e.g., network requests, file I/O, database calls).
- Creates and runs multiple threads.
- Ideal for tasks waiting on external resources (like APIs or file reading).
import threading
import time
def worker(n):
print(f"Thread {n} starting")
time.sleep(2)
print(f"Thread {n} done")
threads = []
for i in range(3):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
Multiprocessing (Process-based parallelism)
- Uses multiple processes instead of threads.
- Bypasses GIL by running processes in separate memory spaces.
- Best for CPU-bound tasks (e.g., mathematical computations, image processing).
- Higher memory usage due to separate memory allocation per process.
- Each task runs in a separate process.
- More memory-intensive but allows real parallel execution.
- May need IPC, will have overhead
import multiprocessing
import time
def worker(n):
print(f"Process {n} starting")
time.sleep(2)
print(f"Process {n} done")
processes = []
for i in range(3):
p = multiprocessing.Process(target=worker, args=(i,))
processes.append(p)
p.start()
for p in processes:
p.join()
Asyncio (Asynchronous programming)
- Uses a single thread and single process but achieves concurrency using an event loop.
- Best for I/O-bound tasks without needing multiple threads or processes.
- Uses coroutines (async functions) that execute in a non-blocking manner.
- Uses await to allow other tasks to run while waiting.
- Suitable for tasks like web scraping, database queries, and network requests.
import asyncio
async def worker(n):
print(f"Task {n} starting")
await asyncio.sleep(2)
print(f"Task {n} done")
async def main():
tasks = [worker(i) for i in range(3)]
await asyncio.gather(*tasks)
asyncio.run(main())