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
async fn transfer()three awaitsstate machinestate 0, 1, 2, 3executor / event looppolls or resumesfutures / promisespending → readyreactorepoll / kqueue / io_uring
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

runtimecancellationstructured concurrency
JavaScriptAbortController passed down explicitlyby convention (Promise.all does not cancel siblings)
Pythontask.cancel() raises CancelledError at the next awaitasyncio.TaskGroup, Trio nurseries
Rust (Tokio)dropping a future cancels itJoinSet, scoped tasks
Gocontext.Context passed explicitlyerrgroup.Group
Javathread interruption, Future.cancelStructuredTaskScope (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.