Concurrency Comparisons

Side-by-side trade-offs where neither column wins. The workload, the runtime and how much correctness risk you can carry decide — and each comparison ends with the verdict that follows from that, not from a preference.

Event loop vs thread pool

Two server architectures for the same problem: many clients, limited machine. They fail differently under load, and the failure mode is usually what should pick between them.

DimensionEvent loopThread pool
Concurrency ceilingBounded by memory per connection — very highBounded by thread count and stack memory
Cost of an idle connectionA socket and a small objectA whole thread, if it is thread-per-connection
One slow handlerHead-of-line blocking for every other connectionOccupies one worker; the rest keep serving
CPU-bound requestCatastrophic without offloadingAbsorbed, until all workers are busy
Uses multiple coresNeeds one loop per core, or worker threadsNaturally, if the runtime runs threads in parallel
Shared-state bugsOnly across await pointsAnywhere two handlers touch the same object
Saturation signalEvent-loop lag rises before throughput dropsAll workers busy, queue depth and age climbing
Mental modelOne callback at a time, never interrupted mid-callbackN handlers running truly simultaneously
Use Event loop when
  • Many long-lived, mostly idle connections — chat, streaming, SSE.
  • Handlers are thin: parse, call something, serialize.
  • You can prove nothing CPU-heavy runs on the loop.
Use Thread pool when
  • Handlers do meaningful computation or call blocking libraries.
  • Concurrency is in the hundreds and per-request memory is acceptable.
  • You want one slow request to hurt one worker, not everyone.
Verdict

The question is not which is faster; it is which failure you prefer. An event loop degrades globally and gracefully until one handler stalls it; a pool degrades locally and then queues. Most production stacks pick the loop for the edge and a bounded pool for anything that computes.