調(diào)度模型
groutine能擁有強大的并發(fā)實現(xiàn)是通過GPM調(diào)度模型實現(xiàn)
G代表一個goroutine對象贺归,每次go調(diào)用的時候这溅,都會創(chuàng)建一個G對象
M代表一個線程彭羹,每次創(chuàng)建一個M的時候奕筐,都會有一個底層線程創(chuàng)建;所有的G任務(wù)徘钥,最終還是在M上執(zhí)行
P代表一個處理器衔蹲,每一個運行的M都必須綁定一個P,就像線程必須在么一個CPU核上執(zhí)行一樣
每一個P保存著本地G任務(wù)隊列吏饿,也有一個全局G任務(wù)隊列踪危。
調(diào)用go時
創(chuàng)建一個G對象,加入到本地隊列或者全局隊列
如果還有空閑的P猪落,則創(chuàng)建一個M,如果沒找到則直接返回
M會啟動一個底層線程畴博,循環(huán)執(zhí)行能找到的G任務(wù)
G任務(wù)的執(zhí)行順序是笨忌,先從本地隊列找,本地沒有則從全局隊列找(一次性轉(zhuǎn)移(全局G個數(shù)/P個數(shù))個俱病,再去其它P中找(一次性轉(zhuǎn)移一半)官疲,
以上的G任務(wù)執(zhí)行是按照隊列順序(也就是go調(diào)用的順序)執(zhí)行的。
搶占式調(diào)度
啟動的時候亮隙,會專門創(chuàng)建一個線程sysmon途凫,用來監(jiān)控和管理
記錄所有P的G任務(wù)計數(shù)schedtick,(schedtick會在每執(zhí)行一個G任務(wù)后遞增)
如果檢查到 schedtick一直沒有遞增溢吻,說明這個P一直在執(zhí)行同一個G任務(wù)维费,如果超過一定的時間(10ms),就在這個G任務(wù)的棧信息里面加一個標記(stackguard設(shè)置為StackPreempt然后相當于調(diào)用runtime.Gosched)
然后這個G任務(wù)在執(zhí)行的時候促王,如果遇到非內(nèi)聯(lián)函數(shù)調(diào)用犀盟,就會檢查一次這個標記,然后中斷自己蝇狼,把自己加到隊列末尾阅畴,執(zhí)行下一個G