NOTE
3.1 GMP
Goroutine scheduler, GM model, GMP model, P/M/G, goroutine creation flow, preemptive scheduling, and references.
This is a historical learning note and may contain outdated or incomplete understanding.
1. Goroutine Scheduler
- The coroutine scheduling model in Golang: given M threads and N goroutines, how should goroutines be assigned to threads for execution?
- This is essentially similar to an operating-system scheduler: given M processors and N threads, how should processors be assigned to threads for execution?
1.1. GM Model
- The GM model was used at first.
- G: goroutine; M: kernel thread.
- In this model, all Gs are placed in a global queue. M needs to lock when taking Gs from or putting Gs back into the global queue.
- Problems:
- Locking is inefficient.
- Poor locality.

1.2. GMP Model
- To solve the disadvantages of the GM model, the GMP model was introduced. M binds to P; P has a local queue that stores goroutines; M takes goroutines from it for execution. If P’s local queue is empty, it gets work from the global queue or steals from another P.
- In one sentence: M needs to obtain a P before it can run a G.

1.2.1. P
- Processor, an abstract processor.
- The
GOMAXPROCSenvironment variable orruntime.GOMAXPROCS()sets how many operating-system threads can execute Go code at the same time, i.e. the number of Ps in GMP.
1.2.2. M
-
Machine, a kernel thread.
-
Ms are created by the Go runtime as needed; the operating-system thread limit can be configured through
runtime/debug.SetMaxThreads, whose default limit is 10,000. -
If an M blocks, a new M will be created.
-
If an M is idle, it will be reclaimed or put to sleep.
1.2.3. G
- Goroutine, a coroutine.
- Executes user code.
runtime.NumGoroutine()gets the current total number of goroutines, i.e. the number of Gs in GMP.- The number of Gs can also be obtained through pprof.md.
2. Flow for the Scheduler to Create a Goroutine

2.1. Initialize M0 and G0
- M0
- The main thread with number 0 after the program starts.
- Responsible for initialization and starting the first G.
- G0
- Each time a new M is started, a G is created. This first created G is G0.
- Responsibilities:
- Schedule other goroutines that execute on M.
- Create other goroutines.
- Execute GC.
- Grow stacks.
2.2. go func Execution Flow

3. Preemptive Scheduling
At first, coroutine scheduling in user space was cooperative: only after one coroutine yielded the CPU would the next coroutine execute. Later, to prevent one goroutine from running for too long, it was changed to preemptive scheduling.
Preemption timing:
- Goroutines blocked in system calls for a long time or running for a relatively long time may be preempted; Go 1.14 and later also support asynchronous preemption.
- The runtime has a background detection thread that checks these conditions and notifies goroutines to schedule.
4. References
- [Collector’s Edition] Golang Scheduler GMP Principles and Scheduling: Full Analysis | Go Technical Forum
- Go: g0, Special Goroutine. ℹ️ This article is based on Go 1.13. | by Vincent Blanchon | A Journey With Go | Medium
- Preemptive Scheduling · Deep Dive into Go
- Number of Threads in a Running Go Program | Colobu
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub