Blocking servers vs event-driven servers
“Compare a thread-per-connection server with an event-driven one. What is actually blocking, in the kernel, when a thread "blocks"? When is each design the right one?”
What this tests
- Understanding what a blocked thread is (sleeping in the kernel on a wait queue)
- The difference between concurrency (many waits) and parallelism (many cores)
- The one rule of event loops: never block the loop
- Judgement about when threads are the better tool
Answers by level
Read the beginner answer first and notice what is missing.
When a thread calls recv() on a socket with an empty receive buffer, the kernel puts it on the socket’s wait queue and schedules something else; the thread is not consuming CPU, it is simply not runnable. Its cost is memory (stack, kernel task) and the context switch when it wakes. A thread-per-connection server is easy to write because each handler reads like straight-line code.
An event-driven server keeps one thread (per core) that never blocks on I/O: it registers all sockets with epoll, waits once for any readiness, and runs a short handler per ready socket. The waiting is done by the kernel for all sockets at once, so idle connections cost nothing but memory.
The trade: the event loop must never block — a synchronous file read, a DNS lookup, a CPU-heavy JSON parse, or a sync database driver stalls every connection. Those go to a worker pool. Threads are the right choice when handlers are CPU-heavy, when the language lacks good async I/O, or when connection counts are modest and simplicity wins.
Green flags · Red flags
- Describes a blocked thread as sleeping in the kernel, not spinning
- States the "never block the loop" rule with examples
- Knows the hybrid: loops plus a worker pool
- Can name a case where threads are better
- "Async is faster" with no mechanism
- Thinks blocked threads burn CPU
- Believes event-driven means parallel
- Cannot explain what epoll returns