go調(diào)度機制簡介
go中調(diào)度機制
G-M-P模型
G代表Goroutine即協(xié)程
M表示Machine即工作線程
P表示Processor即處理器
G-P-M關(guān)系
P中維護一個協(xié)程隊列。除此之外還有一個全局的協(xié)程隊列。
G會被放到P中的協(xié)程隊列或者全局隊列中
M必須要綁定一個P才能執(zhí)行G
可以簡單的理解為,P是一個資源池,用來存放G,M從P中取出G來執(zhí)行。M可以理解成廣義上的線程
P的數(shù)量一般是有GOMAXPROCS決定的,M的數(shù)量會略大于P的數(shù)量
調(diào)度過程:以創(chuàng)建新的G為例
創(chuàng)建G時,會先判斷有沒有空閑的P,有的話創(chuàng)建M綁定P,將新的G放到該P隊列中。
如果沒有空閑P,判斷當前P隊列是否滿了,沒滿的話就放到P隊列中,如果滿了,會將P中的一半連同新的G一起放到全局隊列中。
M周期性的從P中取出G來執(zhí)行,并且定期從全局隊列中取出G來執(zhí)行,防止全局隊列中的G被餓死。
當M因為當前G陷入系統(tǒng)調(diào)用或者阻塞時,M會記住當前的P,然后解綁P,P如果沒有G了,就會進入空閑狀態(tài),
如果有G會從M緩存池取空閑的M或者創(chuàng)建一個M
來繼續(xù)執(zhí)行隊列中的G。當M結(jié)束系統(tǒng)調(diào)用時,先找之前的P,沒有找到會找到一個空閑的P,找到了就綁定P,將G放到P隊列中,
繼續(xù)執(zhí)行
如果找不到的話,就將G放到全局隊列中,陷入睡眠狀態(tài)。
當P中的隊列中不存在G,會從全局隊列中取G來執(zhí)行。如果全局隊列也沒有G。就從其他P中偷取,每次偷一半
每個M都有一個G0,用來在調(diào)度或者系統(tǒng)調(diào)用的時候使用其棧空間。
M0除了負責初始化操作和啟動第一個G之后跟其他的M一樣。
G執(zhí)行完成后會切換為G0,然后G0負責調(diào)度協(xié)程切換
上面的文字可能比較抽象,我盡量用簡單的場景來介紹。
以銀行為例。把每個客戶當作G,每個窗口當作P,每個工作人員當作M
每個窗口都有自己的客戶隊列,除此之外,還有一個全局的客戶隊列。
工作人員并不能直接處理客戶請求,需要綁定一個窗口,即M需要綁定P才能從M中取出并運行G
這就是G-M-P的關(guān)系
當客戶進來了,新的G到來。先判斷下有沒有空閑的窗口P?
有,那就去空閑的窗口P,然后窗口P找到一個工作人員M來執(zhí)行客戶請求。
沒有,那么判斷當前窗口P排隊的人是不是滿了,沒滿。那就在當前窗口P排隊。
如果滿了,那么就叫上當前窗口一半的客戶一起到大廳(全局隊列)排隊。
工作人員M會從窗口P中排隊的人找客戶G。并且會定期從大廳的全局隊列叫上客戶G來運行。
防止大廳的客戶等的不耐煩走了,即防止G餓死。
工作人員M處理客戶G的時候可能需要去其他地方找資料,即阻塞。那么就會記住當前窗口P。然后解綁當前窗口P。等資料找到了即G工作執(zhí)行完成,優(yōu)先找到之前綁定的窗口。如果窗口被其他工作人員M占用了,那就看下有沒有空閑的窗口P,沒有的話就去休息,即陷入睡眠狀態(tài),把之前沒執(zhí)行完成的客戶G放到全局隊列里。
窗口P發(fā)現(xiàn)沒有客戶G排隊了,那么就會進入空閑狀態(tài)。就會去大廳找客戶G,大廳里也沒有客戶G,那就去其他窗口偷客戶G,每次偷一半
如果有客戶,那么就創(chuàng)建或找一個工作人員M來執(zhí)行G
個人理解,如有錯誤,歡迎友好交流。