06 — Async¶
async is concurrency without threads: one thread, an event loop, and tasks that give the loop back at every await. It changes the questions. There is no data race to find and no lock to forget, and instead a blocking call anywhere stops everything, a task nobody awaits fails silently, and cancellation is either automatic or impossible depending on the language. The chapter starts by writing the loop itself, so that nothing after it is magic.
Every lesson in this chapter is a stub: the question, the expected answer per language and what the programs will have to show, waiting for the programs. A stub becomes a lesson when its examples run in CI and its table is replaced by what they printed.
| Lesson | The one thing |
|---|---|
| What does an event loop do all day? | stub — one thread, one while: run the ready task to its next await, then sleep in poll until something is |
| What is a future before it has a value? | stub — a Java future is already running; a Rust future does nothing until polled |
What happens at an await? |
stub — await is where a task may stop and hand back its thread, its locals kept in the future |
| What does one blocking call do to every other task? | stub — one blocking call stops every task on the loop for as long as it takes |
| Where does a callback keep its state? | stub — a callback carries its state by hand — closure, void *, object — which is what await was invented to hide |
| How is a running task told to stop, and does it? | stub — Rust drops the future, Python throws at the next await, Go and C leave it to a flag the task checks |
| What happens to the work when an await times out? | stub — the caller gets control back at the deadline; whether the work stops depends on the language |
| Why can't a normal function call an async one? | stub — an async function can only be awaited from an async function, so async spreads upward; Go and virtual threads have no colors |
| What happens to a task that is started and never awaited? | stub — a failure nobody sees, or a wait that never ends, and nothing reports it; structured concurrency makes both impossible |
| How does a loop await a sequence of values that arrive over time? | stub — an iterator whose next is awaited; async for, a channel, Flow.Publisher |
| Who runs an async task, and on how many threads? | stub — one thread or all cores — and on a multi-threaded runtime a task may resume somewhere else |
| How does one thread watch a thousand sockets? | stub — poll, epoll, kqueue: one thread watches a thousand sockets at no cost per idle one |
| Why may only one thread touch the user interface? | stub — one thread owns the widgets; work elsewhere and post the result back |