Blocking vs Non-blocking I/O: How a Thread Waits for Data

Overview Blocking and non-blocking I/O differ in what happens to the calling thread when a read or write can’t complete immediately. Blocking I/O suspends the thread until data is ready; non-blocking I/O returns at once and lets the caller check back later. The choice shapes how a system scales to many simultaneous connections. Comparison Diagram Blocking I/ONon-blocking I/OThreadcall read()thread blockedno other work possibleuntil data arrivesdata ready, resumes1 thread ≈ 1 in-flight callthread / event loopread() returns at oncepoll / epoll checkretrymeanwhile: serves otherconnectionsready → callback fires1 thread ≈ many in-flight calls Comparison Table Aspect Blocking I/O Non-blocking I/O Call behavior Call halts the calling thread until the operation completes Call returns immediately, with data or an EWOULDBLOCK/EAGAIN error Thread state while I/O is pending Thread is suspended off the run queue — no CPU used, but unavailable for other work Thread stays runnable and can be reused to serve other requests How readiness is discovered OS wakes the thread automatically once data is ready Caller polls or registers with select/poll/epoll/kqueue Concurrency model One thread (or process) per concurrent connection Single or few threads multiplex many connections via an event loop Resource overhead at scale Grows linearly with connections — thread stacks, context switches Stays flat, bounded by CPU cores rather than connection count Code / control-flow complexity Simple, sequential, top-to-bottom logic Callback, promise, or async/await structure; state tracked across suspensions Failure / edge-case handling A slow or hung peer blocks the thread indefinitely without a timeout A slow peer only delays its own event; a stalled callback can starve the whole loop Key Differences Blocking I/O ties up a thread for the full call; non-blocking frees it immediately. Non-blocking servers rely on an event loop to learn when data is finally ready. Blocking scales concurrency with more threads; non-blocking scales with more callbacks on fewer threads. Blocking code reads sequentially; non-blocking code needs explicit state management across suspensions. At high connection counts, blocking hits a C10K wall that non-blocking avoids. When to Use Each Blocking I/O ...

August 2, 2026 · 3 min · 488 words · jeonck