Python - Asyncio
Overview
Estimated time: 30–45 minutes
asyncio
enables concurrent I/O via coroutines and an event loop. Learn how to structure async code safely and avoid blocking the loop.
Learning Objectives
- Write coroutines with
async def
andawait
. - Run tasks concurrently and handle cancellations/timeouts.
- Recognize when to use threads/processes vs asyncio.
Prerequisites
- Functions, exceptions; basic understanding of I/O-bound vs CPU-bound work
Examples
import asyncio
async def work(name, delay):
await asyncio.sleep(delay)
return f"{name} done"
async def main():
t1 = asyncio.create_task(work("A", 1))
t2 = asyncio.create_task(work("B", 1.5))
results = await asyncio.gather(t1, t2)
print(results)
asyncio.run(main())
Expected Output:
['A done', 'B done']
Common Pitfalls
- Blocking the event loop with CPU-bound work or synchronous I/O—offload via
asyncio.to_thread
orrun_in_executor
. - Forgetting to handle cancellations and timeouts; use
asyncio.wait_for
andtry/finally
for cleanup. - Mixing sync and async APIs; prefer libraries with native async support.
Best Practices
- Use
asyncio.create_task
for fire-and-forget, track tasks to avoid leaks. - Apply timeouts and cancellation handling; ensure idempotent cleanup.
- Keep coroutines small and composable; avoid deep nesting.
Checks for Understanding
- How do you run two coroutines concurrently and get both results?
- How do you offload CPU-bound work in an async app?
Show answers
- Create tasks and
await asyncio.gather(...)
. - Use
asyncio.to_thread
(3.9+) orloop.run_in_executor
with a ThreadPool/ProcessPool.
Exercises
- Implement concurrent HTTP GETs using
aiohttp
(orhttpx
in async mode) with timeouts. - Demonstrate cancellation of a long-running task and proper resource cleanup.