go 介面 構造器 Golang排程器

2021-10-17 09:39:54 字數 2211 閱讀 2980

go排程器模型

go的排程器可以充分利用多核心cpu,任何時候都有m個go協程在n個系統執行緒上進行排程, 這些執行緒在最多 gomaxprocs 個cpu核心上執行,這種排程模型稱之為gmp模型:

如下圖,每個p都有乙個本地佇列存放待執行的g,另外有乙個全域性佇列,每個m需要依附在p上執行,乙個p可以對應多個m, 但是同一時間乙個p上只會有乙個正在執行的m。

每輪排程只需要找乙個可執行的g執行它就行,這個查詢過程如下:

runtime.schedule()
go協程和執行緒一樣有三種狀態,乙個協程可以處於下面三種狀態中的一種: waiting , runnable 和 executing 。

go程式中的下列4類事件可以觸發排程器執行排程任務。並不是說這些事件發生時排程器一定會執行排程,只是說此時排程器有機會執行排程:

大多數作業系統都支援網路輪詢,例如macos的kqueue,linux的epoll介面。go會利用網路輪詢介面來非同步處理網路請求, 當g呼叫網路系統呼叫時排程器會將此g排程出去以避免m被阻塞,然後排程佇列中的其他g繼續執行,因此不需要建立乙個新的m,減少排程開銷。

在圖1中,goroutine-1正在m上執行,此時本地佇列中有3個g在等待執行,網路輪詢器上是空的。

圖2中,goroutine-1希望進行網路系統呼叫,此時將goroutine-1移至網路輪詢器上處理非同步網路系統呼叫然後將goroutine-2排程到m上繼續執行。

圖3中,網路呼叫完成,此時goroutine-1被放回本地佇列中,當排程到goroutine-1時,它可以繼續執行接下來的指令,這裡最大的好處是執行網路系統呼叫不需要額外的m, 網路輪詢器實際是乙個系統執行緒專門用於處理非同步網路請求。

當g呼叫同步系統呼叫時會怎樣?例如檔案相關的系統呼叫以及使用cgo時呼叫c函式也是同步呼叫,此時m會被此g阻塞。

圖4中,goroutine-1正在m1上執行,他要執行同步系統呼叫,此時會阻塞m1。

圖5中,排程器可以探測出m1被goroutine-1阻塞了,此時排程器會將m1和p分開,但是goroutine-1還是在m1上。 然後搞乙個m2繼續在p上執行,此時可以排程goroutine-2繼續執行。go會維護乙個執行緒池只有執行緒池中沒有m才會建立新的m,所以這種m切換是非常快的。

任務竊取作用是平衡p之間的負載,如果某個p上的g都執行完了,此時會檢查其他p上有沒有可執行的g,如果有則會竊取其他p上的g來執行。

圖7中,有兩個p,每個p上有4個g,全域性佇列中也有乙個g。

圖8中,p1上的g全部執行完了,但是p2和全域性佇列上還有g待執行。此時p1需要竊取其他g來執行,竊取規則和排程規則是一樣的參考上面的 runtime.schedule 。

圖9中,根據竊取規則,p1會將p2上一半的g竊取過來執行。

圖10中,如果此時p2上的g都執行完了,並且p1的本地佇列中也沒有g了會怎麼辦?

圖11中,p2上的g都執行完,它要開始竊取任務,但是p1上也沒有g了,根據竊取規則他會把全域性佇列上的g拿過來執行。

這篇文章基本上是翻譯下面的文章,然後加了一些自己的理解。

Golang排程器GMP模型

g goroutine 我們所說的協程,為使用者級的輕量級執行緒,每個goroutine物件中的sched儲存著其上下文資訊.go1.11版本預設stack大小為2kb stackmin 2048 建立乙個g物件,然後放到g佇列 等待被執行 func newproc1 fn funcval,argp...

Golang 基礎系列十六 Go 語言介面

go 語言中的介面就是方法簽名的集合,介面只有宣告,沒有實現,不包含變數。定義介面 type 介面名 inte ce 例子 type isay inte ce 實現介面 例子 定義介面的實現類 type chinese struct 實現介面 func chinese sayhi 中國人 type ...

Golang排程器GMP學習筆記(二)

我們通過 go func 來建立乙個goroutine 有兩個儲存g的佇列,乙個是區域性排程器p的本地佇列 乙個是全域性g佇列。新建立的g會先儲存在p的本地佇列中,如果p的本地佇列已經滿了就會儲存在全域性的佇列中 g只能執行在m中,乙個m必須持有乙個p,m與p是1 1的關係。m會從p的本地佇列彈出乙...