Reactor
The reactor pattern demultiplexes I/O readiness events on a single loop and dispatches them synchronously to handlers, letting few threads serve many connections. It powers non-blocking, event-driven servers.
The reactor pattern handles many concurrent I/O sources efficiently without a thread per connection. A single event loop waits on an OS readiness mechanism, and when a source becomes ready, the reactor synchronously dispatches the event to a pre-registered handler. This lets one or a few threads service thousands of connections, the foundation of high-performance non-blocking servers.
How It Works
The core components are a synchronous event demultiplexer (epoll, kqueue, IOCP-readiness, select/poll), a reactor that owns the event loop, and event handlers registered for specific events on specific resources. The loop blocks on the demultiplexer until one or more handles are ready (readable, writable), then calls each ready handle's handler synchronously. Handlers perform the actual non-blocking read or write and then process the data. Because dispatch is single-threaded, handlers must not block; long work is offloaded to a worker pool. Node.js's event loop, Netty, libevent, Nginx, and Python's asyncio all build on this model.
When to Use It
Use the reactor pattern for servers that must handle large numbers of mostly-idle or I/O-bound connections — web servers, proxies, real-time gateways, and chat servers — where a thread-per-connection model would exhaust memory and scheduler capacity. It shines when concurrency is dominated by waiting on I/O rather than CPU work.
Trade-offs
A blocking or CPU-heavy handler stalls the entire loop and every connection it serves, so discipline (non-blocking calls, offloading) is mandatory. Logic becomes callback- or coroutine-based, which can be harder to read than straight-line blocking code. A single reactor uses one core; scaling across cores needs multiple reactors (one per core) or a worker pool. The reactor notifies on readiness and the handler does the I/O, which differs from the proactor's completion model.
Related Patterns
The proactor-pattern is the asynchronous-completion counterpart; half-sync-half-async layers a reactor front end over worker threads; and the actor-model shares the single-threaded-dispatch idea at a finer grain.
Example
An API gateway runs one reactor per CPU core, each with an epoll loop. Tens of thousands of idle keep-alive connections cost almost nothing; when requests arrive, handlers read non-blockingly and hand CPU-bound parsing to a worker pool, keeping each event loop responsive while serving far more connections than a thread-per-request server could.