async / await
- Write coroutines with
async defand pause them withawait - Run async functions with
asyncio.run - Fire off many coroutines concurrently with
asyncio.gather - Recognize when async helps (I/O-bound) vs when it doesn't (CPU-bound)
FastAPI, httpx, asyncpg, and Playwright are async-first — a single blocking requests.get in an async endpoint tanks throughput for the whole event loop. Senior engineers know when to reach for asyncio.gather, asyncio.TaskGroup (3.11+), and run_in_executor for CPU-bound or legacy sync calls.
- Calling a blocking library inside an async handler — freezes the loop; wrap in
asyncio.to_thread(...). - Forgetting to
awaita coroutine — returns a coroutine object and emitsRuntimeWarning: never awaited. - Sharing one
httpx.AsyncClientacross tasks without anasync with— connection pool leaks under load.
A model for code that waits: network I/O, timers, queues. While one coroutine is waiting, the event loop runs another.
Three keywords
async def— defines a coroutine (a function that returns a coroutine object)await x— pause this coroutine untilxcompletesasyncio.gather(*coros)— run many coroutines concurrently and wait for all
In Pyodide
The browser's event loop is asyncio's event loop. await at the top level Just Works.
Common pitfall
Calling async_fn() without await returns a coroutine object — it does not run. Always await or pass to gather.
Try it
- Convert the three
fetch_thingcalls to run sequentially withawait— observe the time difference. - Use
asyncio.create_taskand check the difference vsgather.
3 graded exercises
Write the code, click Check. We’ll tell you exactly what to fix.
- Exercise 1
Define an
async def hello(name)that returns the string"Hello, <name>". Then run it withasyncio.run(hello("Ada"))and print the result. Expected:Hello, Ada. - Exercise 2
Write an
async def task(n)that awaitsasyncio.sleep(0)and returnsn * n. In amain()coroutine, useasyncio.gather(task(2), task(3), task(4))and print the result list. Expected:[4, 9, 16]. - Exercise 3
In an async main coroutine, launch two coroutines that each
await asyncio.sleep(0.05)and return their arg. Useasyncio.gatherand print the tuple/list of results. Expected includes both"a"and"b".