Demystifying Go's Scheduler: How Goroutines, M, P, and G Work Together
This article explains the inner workings of Go's runtime scheduler, detailing how lightweight goroutines (G), logical processors (P), and OS threads (M) interact, how work stealing operates, and how to trace scheduler behavior using GODEBUG and go tool trace.
1. Basics
Go's runtime manages scheduling, garbage collection, and the execution environment for goroutines. The scheduler maps goroutines to OS threads. Each goroutine is represented by a G struct that tracks its stack and state. Logical processors, called P, hold queues of runnable Gs, and OS threads, called M, execute the Gs assigned to a P.
The number of logical processors can be set with runtime.GOMAXPROCS(numLogicalProcessors), after which the runtime handles scheduling automatically.
2. The Dance Between Ms, Ps & Gs
The interaction among Ms, Ps, and Gs is complex. A global run queue exists in the schedt structure, but each P maintains its own local run queue of Gs.
When a new goroutine is created (e.g., via go func()), it is placed on the P's queue. If a M finishes executing a G and its P's queue is empty, it randomly steals half of the runnable Gs from another P.
Blocking system calls are intercepted; the runtime detaches the M from its P and creates a new OS thread if needed. When the system call returns, the goroutine is placed back on a local run queue and the thread may become idle.
Network calls are handled similarly, using Go's integrated network poller.
If the current goroutine blocks, the runtime runs a different goroutine. Typical blocking events include:
Blocking system calls (e.g., opening a file)
Network input
Channel operations
Synchronization primitives from the sync package
3. Scheduler Tracing
Go allows tracing of the runtime scheduler via the GODEBUG environment variable.
$ GODEBUG=scheddetail=1,schedtrace=1000 ./programExample output:
SCHED 0ms: gomaxprocs=8 idleprocs=7 threads=2 spinningthreads=0 idlethreads=0 runqueue=0 gcwaiting=0 nmidlelocked=0 stopwait=0 ...
P0: status=1 schedtick=0 syscalltick=0 m=0 runqsize=0 gfreecnt=0
P1: status=0 ...
M0: p=0 curg=1 mallocing=0 throwing=0 preemptoff= locks=1 dying=0 helpgc=0 spinning=false blocked=false lockedg=1
G1: status=8() m=0 lockedm=0For most use‑cases you can simplify the command: $ GODEBUG=schedtrace=1000 ./program An advanced tool, go tool trace, provides a UI to explore program execution in detail.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
360 Zhihui Cloud Developer
360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
