Timeout and cancellation
asyncio.timeout is Python 3.11. The model prints while it is being cancelled, so you can see the cleanup run.
asyncio.gather and TaskGroup (Python 3.11) run many coroutines together, asyncio.timeout (Python 3.11) stops slow work, cancellation lets you stop tasks safely, a Semaphore limits how many run at once, and to_thread hands blocking code to a thread. These are the building blocks of every async LLM client.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 6 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Use gather to run double(1), double(2), double(3) (each sleeps 0.01 and returns n * 2) and print the list.
Write first_with_timeout(seconds), which runs asyncio.sleep(0.2) inside asyncio.timeout(seconds) and returns "done" or "timed out". Test it with 0.05 and 0.5.
Make an asyncio.Lock() and a counter that starts at 0. Write a coroutine add_one that, inside async with lock:, reads the counter, runs await asyncio.sleep(0.01), then stores the read value plus 1. Run five of them with gather and print the final counter (it should be 5).
Explain it without notes
What is the difference between asyncio.gather and asyncio.TaskGroup when one task fails?
How does cancellation work in asyncio, and why must you re-raise CancelledError?
How do you limit a batch of 500 LLM calls to 10 at a time?
When do you use asyncio.to_thread, and what does it not do?
A coroutine is awaiting asyncio.gather(a(), b(), c()) and the coroutine itself gets cancelled. What happens to a, b and c? And what if b raises instead?
Expected output
model: thinking
model: cancelled, cleaning up
model: finally always runs
caller: timed out
model: thinking
model: cancelled, cleaning up
model: finally always runs
caller: task.cancelled() is True