Go: g0, 特殊的goroutine
:information_source: 本文基於Go 1.13
Go中創造所有的goroutine都是由內部的調度器管理。Go調度器會嘗試爲所有goroutine分配運行時間,並在當前goroutine被阻止或終止時使所有CPU忙於運行goroutine。它實際上是作爲特殊的goroutine運行的。
調度協程
Go通過 GOMAXPROCS
變量限制了運行的系統線程數。這意味着Go必須在每個正在運行的線程上調度和管理goroutine。該角色被委派給名爲 g0
的特殊goroutine,這是爲每個系統線程創建的第一個goroutine:
然後,它將安排就緒的goroutine在系統線程上運行。
爲了更好地瞭解在 g0
上的調度方式,讓我們回顧一下通道的使用情況。這是當goroutine阻塞在通道上發送時:
ch := make(chan int)
[...]
ch <- v
在通道上阻塞時,當前goroutine將被停放,即處於等待模式,並且不會在任何goroutine隊列中被推送:
然後, g0
替換goroutine並進行第一輪調度:
在調度期間,本地隊列擁有優先級,並且goroutine#2現在將運行:
一旦接收器將讀取通道,則goroutine#7將被解除阻塞:
v := <-ch
接收到消息的goroutine將切換到 g0
並通過將其放置在本地隊列中來解鎖停放的goroutine:
特殊的goroutine除了管理調度,它還有更多的職責。
職責範圍
與一般goroutine相反, g0
擁有固定的較大的棧。這樣,Go可以在需要更大棧並且在不希望棧增長的情況下執行操作。在 g0
的職責中,我們可以列出:
-
Goroutine創建。當調用
go func(){ ... }()
或go myFunction()
時,Go會將函數創建委託給g0
,然後再將其放置在本地隊列中。新創建的goroutine優先運行,並放置在本地隊列的頂部。
-
Defer方法分配。
-
Gc操作,例如stw,掃描goroutine的棧以及一些標清操作。
-
棧增長。在需要時,Go會增加goroutine的大小。該操作由
g0
在prolog方法中完成。
這個特殊的goroutine g0
涉及許多其他操作(大量分配,cgo等),使我們的程序可以更高效地管理操作,並且需要更大的棧,以保持我們的程序在低內存下更加高效。
編譯整理自 Go: g0, Special Goroutine
https://medium.com/a-journey-with-go/go-g0-special-goroutine-8c778c6704d8