Learn

How schedulers wake sleeping work

A practical look at runqueues, parking, and why latency spikes hide in "idle" systems.

How schedulers wake sleeping work

Most systems spend more time waiting than computing. The interesting engineering is not the busy loop — it is how work gets from "parked" back onto a CPU without thrashing.

The shape of a wakeup

When a goroutine (or thread) blocks on I/O, a channel, or a timer, the runtime records:

  1. Why it parked (wait reason).
  2. Where it should resume (stack / continuation).
  3. Who is allowed to wake it (network poller, timer heap, another P).

A wakeup is then a small, carefully ordered handoff: mark runnable → put on a local or global runqueue → signal an idle processor if needed.

Why local queues matter

Pushing every woken unit onto a single global queue creates contention. Runtimes prefer local runqueues per processor, with work-stealing as a safety valve. That keeps the common path cache-friendly and only pays for steals when load is uneven.

What to watch in production

  • Tail latency after traffic lulls: idle processors take longer to notice new work.
  • Spurious wakes: waking more workers than ready tasks burns CPU for nothing.
  • Timer coalescing: coarse timers reduce wake storms; fine timers amplify them.

Deep-dives like this are how we learn systems — starting from concrete runtime behavior and working outward. More topics land under Learn.