golang排程器原理與GMP模型設計思想

2022-02-23 23:13:18 字數 2193 閱讀 5029

n:1  1.⽆法利⽤多個cpu  2.出現阻塞的瓶頸

1:1   1.跟多執行緒/多程序模型⽆異  2.切換協程成本代價昂貴

m:n  1.能夠利⽤多核 2.過於依賴協程排程器的優化和算 法

記憶體佔⽤ ⼏kb ⼤量開闢

靈活排程 切換成本低

早期的go的排程器 基本的全域性go佇列和⽐較傳統的 輪詢利⽤多個thread去排程

弊端1. 建立、銷毀、排程g都需要每個m獲取鎖,這就形成了激烈的鎖競爭。

2. m轉移g會造成延遲和額外的系統負載。

3. 系統調⽤(cpu在m之間的切換)導致頻繁的執行緒阻塞和取消阻塞操作增加了系統開銷。

g:goroutine 協程

m:thread 核心執行緒

p:processor 處理器

全域性佇列 存放等待運⾏的g

p的本地佇列:  1存放等待運⾏的g 2數量限制 不超過256g 3 優先將新建立的g放在p的本地隊 列中,如果滿了會放在全域性佇列 中

p列表: 1程式啟動時建立 2最多有gomaxprocs個(可配置)

m列表: 當前作業系統分配到當前go程式的核心執行緒數

p的數量: 1.環境變數$gomaxprocs  2.在程式中通過runtime.gomaxprocs() 來設定

m的數量問題: 1.go語⾔本身 是限定m的最⼤量是10000(忽略) 2.runtime/debug包中的setmaxthreads函式來設定 3.有⼀個m阻塞,會建立⼀個新的m 4.如果有m空閒,那麼就會**或者睡眠

1.復⽤執行緒 避免頻繁的建立、銷毀執行緒,⽽是對執行緒的復⽤。

(1)work stealing機制 當本執行緒⽆可運⾏的g時,嘗試 從其他執行緒繫結的p偷取g,⽽不 是銷毀執行緒。

(2)hand off機制 當本執行緒因為g進⾏系統調⽤阻 塞時,執行緒釋放繫結的p,把p轉 移給其他空閒的執行緒執⾏。

2.利⽤並⾏ gomaxprocs設定p的數量,最多有gomaxprocs個執行緒分布在多個cpu上同時運⾏。

3.搶占 在coroutine中要等待⼀個協程主動讓出cpu才執⾏下⼀個協程,在go 中,⼀個goroutine最多佔⽤cpu 10ms,防⽌其他goroutine被餓死

4.全域性g佇列 當m執⾏work stealing從其他p偷不到g時,它可以從全域性g佇列獲取g。

1、我們通過 go func()來建立⼀個goroutine;

2、有兩個儲存g的佇列,⼀個是區域性排程器p的本地佇列、⼀個是全域性g佇列。新建立的g會先 儲存在p的本地佇列中,如果p的本地佇列已經滿了就會儲存在全域性的佇列中;

3、g只能運⾏在m中,⼀個m必須持有⼀個p,m與p是1:1的關係。m會從p的本地佇列彈出⼀個可執 ⾏狀態的g來執⾏,如果p的本地隊列為空,就會想其他的mp組合偷取⼀個可執⾏的g來執⾏;

4、⼀個m排程g執⾏的過程是⼀個迴圈機制;

5、當m執⾏某⼀個g時候如果發⽣了syscall或則其餘阻塞操作,m會阻塞,如果當前有⼀些g在執⾏, runtime會把這個執行緒m從p中摘除(detach),然後再建立⼀個新的作業系統的執行緒(如果有空閒的執行緒可 ⽤就復⽤空閒執行緒)來服務於這個p;

6、當m系統調⽤結束時候,這個g會嘗試獲取⼀個空閒的p執⾏,並放⼊到這個p的本地佇列。如果獲取不 到p,那麼這個執行緒m變成休眠狀態, 加⼊到空閒執行緒中,然後這個g會被放⼊全域性佇列中。

m0 m0是啟動程式後的編號為0的主線程,這個m對應的例項會在全域性變數runtime.m0中,不需要在heap 上分配,m0負責執⾏初始化操作和啟動第⼀個g, 在之後m0就和其他的m⼀樣了。

g0 g0是每次啟動⼀個m都會第⼀個建立的gourtine,g0僅⽤於負責排程的g,g0不指向任何可執⾏的函式, 每個m都會有⼀個⾃⼰的g0。在排程或系統調⽤時會使⽤g0的棧空間, 全域性變數的g0是m0的g0。

建立trace⽂件 f, err := os.create("trace.out")

啟動trace trace.start(f)

停⽌trace trace.stop()

go build 並且運⾏之後,會得到⼀個trace.out⽂件

go tool trace trace.out

通過進⾏訪問

通過debug trace檢視gmp資訊 

Golang排程器GMP模型

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

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

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

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

單程序時代的問題 多程序 多執行緒的問題 協程的問題m goroutine協程 n thread執行緒 m想要執行 放回g都必須訪問全域性g佇列,並且m有多個,即多執行緒訪問同一資源需要加鎖進行保證互斥 同步,所以全域性g佇列是有互斥鎖進行保護的。問題 建立 銷毀 排程g都需要每個m獲取鎖,這就形成...