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










