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獲取鎖,這就形成...