Part 5 · 2 chapters · ~12 min
async/await Underneath
Async functions as compiler-generated state machines, futures and promises (lazy and eager), executors and reactors, Node's loop, Python asyncio, Rust Tokio, .NET tasks, function colouring, blocking inside async code, cancellation, and structured concurrency.
9
State machines and executors
code
# Python asyncio: run three fetches concurrently, cancel all if one fails (structured concurrency, 3.11+)
async def main():
async with asyncio.TaskGroup() as tg:
a = tg.create_task(fetch("ledger")); b = tg.create_task(fetch("rates")); c = tg.create_task(fetch("limits"))
return a.result(), b.result(), c.result()WHAT async/await COMPILES TO
a state machine driven by an executor, resumed when a future is ready
swipe the figure sideways, or tap expand for full screen
1/5
a function that pauses
An async function can pause at each await and resume later. The compiler (Rust, C#, Python) or engine (JavaScript) turns it into a state machine: each await point becomes a state, and local variables live in the state object instead of on the stack.
each await becomes a statelocals move into an object
10
Cancellation and structured concurrency
| runtime | cancellation | structured concurrency |
|---|---|---|
| JavaScript | AbortController passed down explicitly | by convention (Promise.all does not cancel siblings) |
| Python | task.cancel() raises CancelledError at the next await | asyncio.TaskGroup, Trio nurseries |
| Rust (Tokio) | dropping a future cancels it | JoinSet, scoped tasks |
| Go | context.Context passed explicitly | errgroup.Group |
| Java | thread interruption, Future.cancel | StructuredTaskScope (virtual threads) |
Structured concurrency means child tasks cannot outlive the scope that started them: errors propagate, and siblings are cancelled together. It removes whole classes of leaked tasks and orphaned work.