M:N Scheduler
- The Go scheduler is part of the Go runtime. It is known as M:N scheduler.
- Go scheduler runs in user space
- Go scheduler use OS threads to schedul goroutines for execution.
- Goroutines runs in the context of os threads.
- Go runtime create number of worker OS threads, equal to GOMAXPROCS.
- GOMAXPROCS - default value is number of processors on machine.
- Go scheduler distributes runnable goroutines over multiple worker OS threads.
- At any time, N goroutines could be scheduled on M OS threads that runs on at most GOMAXPROCS numbers of processors.
Asynchronous Preempation(搶佔)
- As of Go 1.14. Go scheduler implements asynchronous preemption.
- This prevents long running Goroutines form hogging onto CPU, that could block other Goroutines.
- The asynchronous preemption triggered based on a time condition. When a goroutine is running for more than 10ms, Go will to preempt it.

MPG
在 n 個操作系統線程上多工調度 m 個 Goroutines
G: Goroutine M: Machine 或 worker thread P: Processor, 只有當M與一個P關聯後才能執行Go程式碼
深色的G:待執行狀態 淺色G: 正在執行
當一個P關聯多個G時, 就會處理G的執行順序, 就是並發. 當一個P在執行一個協程工作時, 其他的會在等待, 當正在執行的協程遇到阻塞情況, 例如IO操作等, go的處理器就會去執行其他的協程, 因為對於類似IO的操作, 處理器不知道你需要多久才能執行結束, 所以他不回去等你執行完。
上面我們看著go的並發好像是搶占式的, 事實上go的協程是非搶占式的, 由協程主動交出控制權, 也就是說, 上面在發生IO操作時, 並不是調度器強制切換執行其他的協程, 而是當前協程交出了控制權, 調度器才去執行其他協程。 我們列舉一下goroutine可能切換的點:
- I/O, select
- channel
- 等待鎖
- runtime.Gosched()
這些點是go協程可能切換的地方,但是並不是一定切換的。
正是因為是非搶占式的,所以才輕鬆的構造上萬的協程,
如果是搶占式,那麼就會在切換任務時,保存當前的上下文環境,
因為當前線程如果正在做一件事,做到一半,我們就強制停止,這時我們就必須多保存很多信息,避免再次切換回來時任務出錯.
