liveBook · Manning

Asynchronous programming

As explained in Latency

Asynchronous processing is a technique in which an operation can proceed or return control before all of its work has completed, allowing other work to continue concurrently.

Asynchronous programming starts an operation without requiring its caller to wait for completion. While I/O is pending, the system can advance other tasks. This differs from synchronous processing, which finishes one task before starting the next. The benefit is often lower perceived latency and better responsiveness—not necessarily faster completion of the underlying I/O. section 10.0 section 10.1.1

A server waiting on I/O

A synchronous server may block while receiving a message, retrieving data, or sending a response. An asynchronous server can monitor connections through I/O multiplexing, process a socket when it becomes ready, and move to other requests while a response is being sent. A web server can likewise initiate a database query, handle other events, then resume the request when the query completes. section 10.1.1 section 9.2.4

An event loop makes this pattern practical: it waits for activity from sources such as network connections and timers, then dispatches events to handlers. Waiting when no events are ready is acceptable; blocking inside a handler is not, because it prevents that loop from handling other work. Linux interfaces such as epoll or io_uring, and macOS kqueue, can supply the events. section 9.2.4

loop {
    let events = wait_for_events();
    for event in events {
        handle_event(event);
    }
}

The short loop separates waiting for events from handling each event. A handler must finish or defer its remaining work so polling can continue. section 9.2.4

Callbacks and futures provide two ways to continue after an operation completes. A callback receives the result when it is ready; a future represents a pending result that a caller can await or combine with later work. Awaiting a future yields the execution slot rather than blocking its thread. Coroutines can similarly suspend and resume, while actors use asynchronous messages instead of shared state. section 9.2.4 section 9.2.5 section 9.2.3 section 9.2.6

Overlap is not free. Many outstanding tasks can exhaust resources, so concurrency needs throttling or backpressure. Dependencies, races, partial failures, and execution order complicate debugging and error handling; timeouts and cancellation need explicit attention. Use asynchronous work where waiting limits responsiveness, and account for these costs rather than treating it as an automatic speedup. section 10.1.3 section 10.8

How Latency covers it

How deep it goes
Explains event-loop dispatch, callbacks, futures, and operational pitfalls, but does not provide a complete asynchronous server implementation.
Examples
Uses socket servers, database queries, and asynchronous file reads to contrast blocking with overlapping work.
What you can do after
Apply it via Rust async/await or event-loop handlers to overlap I/O with other work without blocking handlers.
How it connects
Connects event loops and I/O multiplexing with futures, deferred work, and backpressure.

Also explained in

Compare how 28 books explain asynchronous programming →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Latency. The section links point to the parts of the book it draws on.