OS & Systems FundamentalsI/O Models (Blocking, Non-blocking, Async)Hard⏱️ ~3 min

Reactor vs Proactor: Readiness vs Completion Driven I/O

Reactor Pattern

Reactor demultiplexes events and dispatches to handlers when resources become ready. The event loop calls epoll_wait (Linux) or kqueue (BSD). When a socket is readable, the reactor calls your handler. You then perform the actual I/O operation synchronously.

Readiness notification means the kernel tells you a socket is ready. You must then call read() yourself. If you read less than available, you must track state and read more later. Partial reads and writes require careful buffering.

Proactor Pattern

Proactor initiates async I/O operations and dispatches handlers when operations complete. You call aio_read() with a buffer. The kernel performs the read and signals when done. Your handler receives completed data, not a readiness notification.

Completion notification means the kernel tells you the operation finished. Data is already in your buffer. No partial reads to handle at the application level. But buffer management is trickier: you must pre-allocate buffers for operations in flight.

Platform Support

Linux: epoll is reactor style. io_uring (kernel 5.1+) supports proactor style with true async I/O. Traditional aio is limited and rarely used.

Windows: IOCP (I/O Completion Ports) is proactor style. It notifies on completion, not readiness. High performance Windows servers use IOCP exclusively.

BSD and macOS: kqueue is reactor style but can emulate some proactor behaviors. Most code uses reactor pattern.

💡 Key Insight: Reactor says "socket is ready, do the I/O now." Proactor says "I/O is done, here is the data." Reactor is more common on Linux. Proactor (via io_uring or IOCP) reduces syscalls and improves throughput for high volume workloads.
💡 Key Takeaways
Reactor: readiness notification via epoll or kqueue, then you do the I/O
Proactor: completion notification via io_uring or IOCP, kernel did the I/O
Reactor requires handling partial reads and writes with state tracking
Proactor requires pre-allocated buffers for in-flight operations
Linux: epoll is reactor, io_uring is proactor; Windows IOCP is proactor
📌 Interview Tips
1Explain reactor flow: epoll_wait returns, you call read(), you handle partial data yourself
2Explain proactor flow: submit aio_read with buffer, get completion notification, data is already there
3When discussing Linux I/O, mention io_uring as modern proactor alternative to epoll reactor pattern
← Back to I/O Models (Blocking, Non-blocking, Async) Overview