Loading Academy Hub...
Bypass the Python GIL (Global Interpreter Lock): Multiprocessing for heavy JSON parsing/cryptography vs AsyncIO / ThreadPoolExecutor for concurrent REST API extraction.
[!NOTE] The CPython Global Interpreter Lock (GIL) restricts bytecode execution to a single OS thread per process. Choosing the wrong concurrency model can result in zero speedup or race condition bugs.
| Workload | Recommended Tool | Why |
|---|---|---|
| I/O-Bound (Downloading 10,000 S3 objects, HTTP API ingestion) | asyncio / aiohttp or ThreadPoolExecutor | Threads/tasks sleep while waiting for network sockets; GIL is released during I/O. |
| CPU-Bound (Parsing 10M complex JSON files, image hashing, regex tokenization) | multiprocessing.Pool or ProcessPoolExecutor | Spawns separate Python interpreter processes on each CPU core, bypassing the GIL. |
| Distributed Big Data | PySpark / Ray | Scales across multi-node clusters. |
| Workload Type | Root Bottleneck | Best Python Concurrency Tool |
|---|---|---|
| Thousands of REST / S3 / Snowflake API Calls | Network socket wait (I/O-bound) | asyncio + httpx / aiohttp with asyncio.Semaphore rate limit |
Legacy Blocking SDK Calls (boto3, psycopg2) | Thread releases CPython GIL while waiting on I/O | concurrent.futures.ThreadPoolExecutor |
| Heavy Regex / Crypto / Compression / CPU Parse | CPython GIL allows 1 thread running bytecode at once | ProcessPoolExecutor (spawns separate OS processes) or Arrow/Rust Polars |
Review the production code, company interview Q&As, incident traces, and comprehension quiz inside this lesson.
import asyncio
import aiohttp
from typing import List, Dict
async def fetch_page(session: aiohttp.ClientSession, url: str, sem: asyncio.Semaphore) -> Dict:
async with sem: # Limit concurrent requests to 20 to respect API rate limit
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response:
return await response.json()
async def download_all_pages(urls: List[str]) -> List[Dict]:
sem = asyncio.Semaphore(20)
async with aiohttp.ClientSession() as session:
tasks = [fetch_page(session, url, sem) for url in urls]
return await asyncio.gather(*tasks, return_exceptions=True)
# Fetches 5,000 pages in 12 seconds instead of 45 minutes sequential!
# results = asyncio.run(download_all_pages(endpoint_urls))Process pool hanging indefinitely with 0% CPU usage across workers