Explain the GMP model of the Go scheduler.
Question 149MediumGo 1.22 to 1.25
The scheduler is built from three parts:
- G (goroutine): holds the goroutine's stack, saved registers (
gobuf) and status (_Grunnable,_Grunning,_Gwaiting,_Gsyscall, …). - M (machine): an OS thread. An M runs Go code only while it holds a P.
- P (processor): a logical CPU. It owns the resources needed to run Go code: a local run queue of up to 256 Gs, a
runnextslot, anmcachefor allocation, and timers. There are exactlyGOMAXPROCSPs.
An M takes a P and runs Gs from that P's queue. If an M blocks in a syscall, the P can be detached and given to another M, so Go code keeps running. The P exists so that the run queue and allocator caches stay with the "right to run Go code" rather than with the thread. This is the Go 1.1 design by Dmitry Vyukov, which removed the single global run-queue lock.
Other pieces worth mentioning are the global run queue, the sysmon thread (it runs without a P), and g0, the per-M scheduler stack.
More on Goroutines & the Scheduler
- Q148How is a goroutine different from an OS thread?
- Q150How does work stealing work, and in what order does a P look for work?
- Q151What does this print with GOMAXPROCS(1), and why?
- Q152What is preemption in Go? Explain cooperative vs. asynchronous preemption (Go 1.14).
- Q153What does this program do on Go 1.13 vs Go 1.14+?
- Q154How does a goroutine's stack grow? What changed from segmented to contiguous stacks?