operating systems30 min

Blocking vs Non-Blocking

How programs wait for I/O and why non-blocking matters

0/9Not Started

Why This Matters

When your program asks the OS to read a file or fetch data from a network, what happens while it waits? In blocking I/O, the entire thread freezes until data arrives. In non-blocking I/O, the thread keeps working on other tasks and gets notified when data is ready.

This distinction shapes the architecture of modern software. It explains why Node.js can handle 10,000 concurrent connections on a single thread, why Python added asyncio, and why your browser does not freeze every time it loads an image. Understanding blocking vs non-blocking is essential for writing responsive, scalable programs.

Define Terms

Visual Model

I/O Request
Blocking
Thread BLOCKED
Data Ready
Non-Blocking
Thread Continues
Event Loop
Callback Fires
blocking
data arrives
non-blocking
later
data ready

The full process at a glance. Click Start tour to walk through each step.

Blocking I/O suspends the thread; non-blocking I/O lets the thread keep working and handles results via callbacks.

Code Example

Code
const fs = require("fs");

// --- BLOCKING (synchronous) ---
// The thread stops here until the file is fully read
console.log("Before blocking read");
const data = fs.readFileSync("file.txt", "utf8");
console.log("File contents:", data);
console.log("After blocking read");
// Output order: Before -> File contents -> After

// --- NON-BLOCKING (asynchronous) ---
// The thread continues immediately; callback fires later
console.log("Before non-blocking read");
fs.readFile("file.txt", "utf8", (err, data) => {
  if (err) throw err;
  console.log("File contents:", data);
});
console.log("After non-blocking read");
// Output order: Before -> After -> File contents

// --- PROMISE-BASED (modern async/await) ---
const fsPromises = require("fs").promises;

async function readNonBlocking() {
  console.log("Before await");
  const data = await fsPromises.readFile("file.txt", "utf8");
  console.log("File contents:", data);
  console.log("After await");
}
readNonBlocking();

Interactive Experiment

Try these exercises:

  • In Node.js, start a blocking file read of a large file. While it reads, try to respond to a setTimeout callback. Notice how the timeout is delayed.
  • Replace the blocking read with fs.readFile (async) and observe how the timeout fires on time.
  • Write a script that makes 5 network requests. Time the total duration using blocking (one after another) vs non-blocking (Promise.all). Compare the results.

Quick Quiz

Coding Challenge

Convert Blocking to Non-Blocking

You are given a blocking function `fetchDataSync` that simulates a slow I/O operation. Write an async version called `fetchAllData` that takes an array of IDs and fetches them all concurrently using Promise.all, returning the results. This demonstrates the performance advantage of non-blocking I/O.

Loading editor...

Real-World Usage

The blocking vs non-blocking choice defines entire software architectures:

  • Node.js / Nginx use non-blocking I/O with event loops. One thread handles thousands of concurrent connections, making them ideal for I/O-bound workloads like APIs and proxies.
  • Apache (traditional) used blocking I/O with a thread-per-connection model. Simple but expensive in memory and context-switch overhead under heavy load.
  • Python asyncio adds non-blocking I/O to Python. Libraries like aiohttp and FastAPI build high-performance web servers using async/await.
  • Database drivers offer both blocking and async variants. Using async drivers prevents your web server from stalling while waiting for query results.

Connections