Why a scheduler exists
“Why does the OS need a scheduler at all, and what is it optimising for? What could go wrong with the simplest scheme you can think of?”
What this tests
- Scheduling as a response to a constraint (more runnable tasks than cores)
- The conflicting goals: throughput, latency, fairness
- Preemption and why cooperative scheduling fails
- What blocked tasks cost and what the application can influence
Answers by level
Read the beginner answer first and notice what is missing.
Start with the constraint: a core executes one instruction stream, and at any moment there may be many tasks that *could* run. Something has to pick, and it has to pick again a few milliseconds later when the situation changes. That something is the scheduler, and it is a policy with conflicting goals — throughput (finish the most work), latency (a keypress or an incoming packet is handled promptly), fairness (no task starves), and increasingly power and cache locality (The Scheduling Problem).
The simplest scheme — run a task until it finishes — collapses on the first infinite loop; nothing else ever runs again. So the scheduler needs preemption: a timer interrupt ends the slice whether the task likes it or not. Cooperative systems (Windows 3.1, classic Mac OS — and every event loop) depend on tasks yielding; one misbehaving task freezes everything, which is exactly what a blocked Node.js event loop looks like (The Event Loop).
The slice length is the central trade-off. Long slices mean fewer switches and better throughput but poor responsiveness; short slices mean the opposite. Schedulers therefore treat tasks differently by behaviour: an I/O-bound task that uses a sliver of its slice and blocks should be run promptly when it wakes; a CPU-bound task can wait. Priorities (nice on Unix, priority classes on Windows) let users and the kernel bias that.
A crucial point that beginners miss: blocked tasks are not scheduled at all. A process sleeping in read() costs the scheduler nothing; it is in a wait queue on the socket, not in the ready queue. The load a scheduler feels is the number of *runnable* tasks, which is what Linux’s load average approximates (with the twist that Linux also counts tasks in uninterruptible I/O wait) (Process States).
Green flags · Red flags
- Frames the scheduler as a policy balancing throughput, latency and fairness
- Explains why preemption is required and what cooperative scheduling breaks
- Says blocked tasks are not in the ready queue
- Distinguishes I/O-bound and CPU-bound behaviour
- Knows nice/priority is a bias, not a guarantee
- Only knows round-robin
- Believes sleeping processes consume CPU or scheduler time
- Thinks a higher priority makes code run faster