Home/Labs/C10K I/O Multiplexing Lab
All 280 Labs
INTERACTIVE LAB🚦

Blocking vs Non-Blocking I/O Lab (Interactive)

Route 100K sockets through thread-per-connection, select, poll, epoll, and io_uring models. Compare memory, syscalls, and per-event kernel scanning across the five classical I/O models as connection count and activity ratio change.

C10K: Blocking I/O vs epoll vs io_uring

Route 10,000 sockets through five classic I/O models and measure the kernel tax per event.

Kernel red-black tree + ready list: callbacks push only ACTIVE sockets; epoll_wait returns instantly.

10,000
2%
50
Kernel overhead CPU (1 core)
0.0%
Memory footprint
26 MB
Events / sec processed
10,000
Syscalls / sec
20,000

200 of 10,000 sockets are ready this instant.

select()/poll() pay scanning only the 200-entry ready list per wakeup — that O(N) vs O(ready) gap is why Nginx, Envoy, Redis and Node.js all sit on epoll/kqueue.

io_uring removes the last ~2.4 μs of syscall transitions (epoll_wait + read) under Spectre-mitigated KPTI by sharing SQ/CQ rings in memory.

How It Works Under the Hood

The C10K problem exposed thread-per-connection’s fatal math: 10,000 idle sockets means 10,000 stacks and wakeup context switches. select() and poll() scan all O(N) descriptors per event — and select caps at 1,024 fds. epoll flips the model: NIC interrupts push ready sockets onto a kernel list, so cost scales with activity, not population. io_uring removes the remaining syscall transitions with shared submission/completion rings.

Core Architectural Principles

  • Blocking model memory = connections x thread stack; multiplexed models pay per active socket only.
  • select/poll cost grows with total fds; epoll returns only the ready list in O(active).
  • io_uring’s SQ/CQ shared rings drive the syscall rate for I/O to zero.
Interview Round Script

For realtime server designs say: "one epoll/kqueue loop per core, edge-triggered, no thread-per-connection" and know why — O(1) ready-list dispatch. Then level up: mention io_uring for high-IOPS storage engines and warn that a single CPU-bound handler freezes every socket on the loop.

Key Trade-Offs

Multiplexing scales connections on tiny memory but forces state-machine-style code, while thread-per-connection stays simple and dies around 10K clients.

Related Curriculum Chapter

Blocking vs Non-Blocking & Asynchronous I/O

Read Full Chapter Blueprint

Explore More Interactive Labs

View All 280 Labs