### Day 2 — asyncio fundamentals (event loop, tasks, gather) #### Goals (what "done" means) - [ ] I can explain the event loop + coroutines + tasks in plain language. - [ ] I can write a small asyncio program using `create_task` + `gather`. - [ ] I can add timeouts, cancellation handling, and concurrency limits. #### Reading (official first) - [ ] Read (core usage): [Coroutines and Tasks — Python docs](https://docs.python.org/3/library/asyncio-task.html) - [ ] Note what each does: `asyncio.run`, `asyncio.create_task`, `asyncio.gather`, cancellation. - [ ] Read (practical walkthrough): [Python’s asyncio: A Hands-On Walkthrough (Real Python)](https://realpython.com/async-io-python/) - [ ] Write 5 bullets: when asyncio is a good fit, and when it’s not. - [ ] Read (debugging): [Developing with asyncio — Python docs](https://docs.python.org/3/library/asyncio-dev.html#debug-mode) - [ ] Note 2 debugging tips you can reuse later. #### Hands-on (build incrementally) 1. **Minimal concurrency demo (no external libs)** - [ ] Write `async def worker(i):` that does `await asyncio.sleep(...)` and returns a value - [ ] Run N workers concurrently with `asyncio.gather` - [ ] Print start/end timestamps to show concurrency 2. **Add concurrency limit** - [ ] Add `asyncio.Semaphore(k)` and wrap the worker body so only `k` run at once - [ ] Demonstrate by running N=50 with k=5 and showing batching behavior 3. **Add timeouts + error isolation** - [ ] Wrap each worker with `asyncio.wait_for(..., timeout=...)` - [ ] Make some workers intentionally exceed timeout - [ ] Use `gather(..., return_exceptions=True)` and summarize: - [ ] successes - [ ] timeouts - [ ] other exceptions 4. **Cancellation behavior** - [ ] Trigger cancellation of a running task and confirm you handle `asyncio.CancelledError` cleanly - [ ] Write 3 bullets: what cancellation means and how to design for it #### Write-up (in notes) - [ ] "Mental model" section (8–10 bullets): - [ ] coroutine vs task - [ ] scheduling - [ ] awaiting vs creating tasks - [ ] why blocking calls break concurrency - [ ] "Pitfalls" section (at least 5 bullets): - [ ] blocking I/O - [ ] CPU-bound work in asyncio - [ ] forgetting to await - [ ] unhandled exceptions in tasks - [ ] cancellation edge cases #### Deliverables (to commit) - [ ] `notes.md` updated with: - [ ] mental model bullets - [ ] code snippets or links to your local scripts - [ ] brief results/observations - [ ] `asyncio_demo.py` (or similar) added with instructions to run #### Suggested commits - [ ] `day02: add asyncio notes + minimal gather demo` - [ ] `day02: add semaphore, timeout, and cancellation examples`