Python Asyncio
Write concurrent Python code with asyncio - async/await syntax, event loop, tasks, gathering, timeouts, and async HTTP with aiohttp.
skill: Python Asyncio category: Backend tags: [Asyncio, Python, Async, Concurrency, aiohttp] readingTime: 6
Asyncio is the right tool for I/O-bound concurrency - making 100 API calls concurrently instead of sequentially. For CPU-bound work, use multiprocessing instead - asyncio runs on a single thread and provides no CPU parallelism. The mental model: async/await is cooperative multitasking - a coroutine yields control when waiting for I/O.
Workflow
- Understand async/await basicsasync def defines a coroutine - a function that can pause at await points and let other coroutines run while waiting.
- Run tasks concurrently with gatherSequential awaits run one at a time. asyncio.gather runs multiple coroutines concurrently - all I/O waits happen in parallel.
- Add timeouts and error handlingAsync I/O that never resolves hangs forever without timeouts. Use asyncio.timeout (Python 3.11+) or asyncio.wait_for.
- Control concurrency with semaphoresasyncio.gather with 10,000 tasks can overwhelm the target server or exhaust file descriptors. Semaphores cap concurrent operations.
- Integrate async with sync codeCalling async from sync code (e.g., Django views) or sync from async code requires bridging the event loops correctly.
Output Format
Asyncio patterns: async/await, gather for concurrency, Semaphore for rate limiting, asyncio.timeout, and run_in_executor for sync code.
async def main():
sem = asyncio.Semaphore(20)
async with aiohttp.ClientSession() as session:
tasks = [limited_fetch(sem, session, url) for url in urls]
results = await asyncio.gather(*tasks, return_exceptions=True)
asyncio.run(main())Examples
Input
Output
Edge Cases & Gotchas
- Blocking sync code in async context - time.sleep() in an async function blocks the entire event loop. Use await asyncio.sleep() or run_in_executor for blocking calls.
- Shared mutable state - asyncio runs coroutines on a single thread - no GIL issues. But coroutines that interleave writes to shared state can corrupt it. Use asyncio.Lock.
- Unclosed client sessions - aiohttp.ClientSession not closed in a finally block leaks connections. Always use async with for session management.
- Cancellation handling - When a task is cancelled (asyncio.CancelledError), cleanup code in finally blocks must be non-blocking async operations.
When to Break These Rules
- Use multiprocessing.Pool for CPU-bound parallelism - asyncio adds zero benefit for computation-heavy code.
- Use Trio instead of asyncio for stricter structured concurrency guarantees - Trio's nursery model prevents "fire and forget" task leaks.
Reference Files
https://docs.python.org/3/library/asyncio.htmlhttps://docs.aiohttp.org/