hardBackend EngineerTechnology
How does Python's async/await work under the hood, and when should you use asyncio vs threading vs multiprocessing?
Posted 18/04/2026
by Mehedy Hasan Ador
Question Details
At a web scraping company:
> "We need to scrape 10,000 URLs. Using threading with 50 workers takes 5 minutes. Using asyncio with aiohttp takes 45 seconds. Why is asyncio so much faster here?"
> "We need to scrape 10,000 URLs. Using threading with 50 workers takes 5 minutes. Using asyncio with aiohttp takes 45 seconds. Why is asyncio so much faster here?"
Suggested Solution
async/await Under the Hood
Python'sasyncio uses a single-threaded event loop (similar to Node.js):import asyncio
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
# Run 10,000 requests concurrently
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
asyncio.run(main())
The Event Loop
1. fetch(url1) → starts HTTP request → awaits response → YIELDS control
2. fetch(url2) → starts HTTP request → awaits response → YIELDS control
3. ... 10,000 requests in flight, one thread handling all
4. Response arrives for url1 → resume fetch(url1) → return data
When to Use What
Why asyncio Was Faster for Scraping
Common Pitfalls
❌ Blocking the event loop
async def handler():
time.sleep(5) # BLOCKS THE ENTIRE EVENT LOOP
# No other coroutines can run for 5 seconds!
✅ Non-blocking
async def handler():
await asyncio.sleep(5) # Yields to event loop
❌ Running CPU work in async
async def process():
result = heavycomputation(data) # Blocks event loop
✅ Offload to process pool
async def process():
loop = asyncio.geteventloop()
result = await loop.runinexecutor(None, heavycomputation, data)