async/await and coroutines
Reading a recipe, you reach a step that says 'let the dough rise for an hour'. A foolish cook stands frozen at the bowl for an hour. A sensible cook bookmarks the recipe, goes and chops vegetables for a different dish, and comes back when the timer rings. async/await lets a function do exactly that: at an await point it can suspend — bookmark itself and step aside — while a slow operation finishes, freeing the thread to run other work, then resume right where it left off.
A function marked async is a coroutine: a function that can pause partway through and be resumed later, unlike an ordinary function which runs start-to-finish without ever stepping aside. await marks a suspension point. When you write let data = await fetch(url), the meaning is: start the fetch; if it is not done, suspend this coroutine and hand the thread back to the executor to run something else; when the fetch completes, resume this function at this exact line with data bound. The compiler/runtime saves the coroutine's local variables and its 'where was I' position across the suspension. Stackless implementations (Rust async, C++20 coroutines) compile each async function into a state machine — an object whose 'state' field records which await it is paused at. Stackful ones (goroutines, fibers) keep a whole separate stack and just park it. Either way, suspend/resume is cooperative: the coroutine yields voluntarily at await points, the runtime is never forced to interrupt it.
This matters because it lets one thread juggle thousands of waiting operations — a web server handling 10,000 idle connections needs 10,000 cheap suspended coroutines, not 10,000 expensive OS threads. The crucial honest point, the one beginners trip on: await does NOT mean 'run in parallel' and async does NOT make code multi-threaded. async/await is about not wasting a thread while waiting; it expresses concurrency (many tasks in flight), which may or may not run on multiple threads. And if your async function does real blocking work between awaits, it hogs the thread and stalls every other task on it — see the don't-block-the-executor rule.
async fn handle(c: Conn) { let req = read(c).await; let resp = db_query(req).await; write(c, resp).await; } // three await points where the task can suspend; between them it holds the thread.
At each .await the coroutine may yield the thread; it resumes on the next line when the awaited result is ready.
async/await is concurrency, not necessarily parallelism. It does not spawn threads by itself, and an async function with no real suspension still runs synchronously. The win is reusing one thread across many waits, not adding cores.