liveBook · Manning

Event loop

As explained in Latency

An event loop is a control-flow pattern that waits for events, detects activity from event sources, and dispatches events to handlers.

An event loop coordinates asynchronous I/O. It watches many event sources—sockets, files, and timers—and dispatches activity to handlers when each source is ready. Instead of dedicating a worker to every connection, it lets a server manage many connections while waiting for I/O. section 10.1.2 section 9.2.4

The loop repeats a short sequence:

  • Poll registered sources for events. OS interfaces include epoll and io_uring on Linux, kqueue on macOS, and IOCP on Windows. Polling may block while there is no work to do. section 10.1.2 section 9.2.4
  • Dispatch each event to its handler, then run scheduled tasks. A handler must not block the loop: it should finish its work or defer work that cannot yet complete. section 10.1.2 section 9.2.4
struct EventLoop {
    // Holds registered event sources like sockets, files, timers
    sources: Vec<EventSource>,    
}

impl EventLoop {
    fn run(&mut self) {
        loop {
            // Create a new collection to store events
            let mut events = Events::new();

            // Poll for new events with a timeout
            self.poll(&mut events, Duration::from_millis(100));

            // Process each event that was found
            for event in events.iter() {
                self.process_event(&event);
            }

            // Run any scheduled tasks
            self.run_scheduled_tasks();
        }
    }
}

A basic Rust loop makes the control flow concrete: poll with a timeout, process the returned events, run scheduled tasks, and repeat. The OS-specific polling operation remains behind poll(). section 10.1.2

Serving a request without waiting on its I/O

A synchronous server receives, parses, processes, and responds to one request before starting another. With an event loop, a readable socket triggers request handling; work that must wait, such as a database query, is started asynchronously. The loop handles other events until completion triggers the request’s continuation. Connection acceptance, reading, writing, and timer expiry can each be handled as separate events. section 10.1.1 section 9.2.4 section 10.1.2

Callbacks can express what happens when an operation completes. Futures and promises offer another way to defer execution; in async Rust, a runtime such as Tokio supplies the event loop. For low-latency systems, consider the allocation, retained state, and synchronization overhead of many futures rather than assuming the abstraction is free. section 9.2.4 section 9.2.5

How Latency covers it

How deep it goes
Works through a basic Rust polling loop and event dispatch, leaving OS-specific multiplexing behind a poll() method.
Examples
Uses socket readiness, timer expiry, request handling, and a Rust polling loop to illustrate dispatch.
What it assumes
Assumes basic familiarity with sockets and request handling while introducing I/O polling interfaces by name.
What you can do after
Evaluate/understand when an event loop can keep an I/O-bound server responsive and why blocking handlers undermine it.
How it connects
Links I/O multiplexing and non-blocking handlers to callbacks, futures, and asynchronous processing.

Also explained in

Compare how 11 books explain event loop →

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.