golang的goroutine調(diào)度機(jī)制

調(diào)度器

主要基于三個基本對象上恶阴,G,M豹障,P(定義在源碼的src/runtime/runtime.h文件中)

  1. G代表一個goroutine對象冯事,每次go調(diào)用的時候,都會創(chuàng)建一個G對象
  2. M代表一個線程沼填,每次創(chuàng)建一個M的時候桅咆,都會有一個底層線程創(chuàng)建;所有的G任務(wù)坞笙,最終還是在M上執(zhí)行
  3. P代表一個處理器岩饼,每一個運(yùn)行的M都必須綁定一個P,就像線程必須在么一個CPU核上執(zhí)行一樣

P的個數(shù)就是GOMAXPROCS(最大256)薛夜,啟動時固定的籍茧,一般不修改;
M的個數(shù)和P的個數(shù)不一定一樣多(會有休眠的M或者不需要太多的M)(最大10000)梯澜;每一個P保存著本地G任務(wù)隊列寞冯,也有一個全局G任務(wù)隊列;
如下圖所示


全局G任務(wù)隊列會和各個本地G任務(wù)隊列按照一定的策略互相交換(滿了,則把本地隊列的一半送給全局隊列)
P是用一個全局?jǐn)?shù)組(255)來保存的吮龄,并且維護(hù)著一個全局的P空閑鏈表

每次go調(diào)用的時候俭茧,都會:

  1. 創(chuàng)建一個G對象,加入到本地隊列或者全局隊列
  2. 如果還有空閑的P漓帚,則創(chuàng)建一個M
  3. M會啟動一個底層線程母债,循環(huán)執(zhí)行能找到的G任務(wù)
  4. G任務(wù)的執(zhí)行順序是,先從本地隊列找尝抖,本地沒有則從全局隊列找(一次性轉(zhuǎn)移(全局G個數(shù)/P個數(shù))個毡们,再去其它P中找(一次性轉(zhuǎn)移一半),
  5. 以上的G任務(wù)執(zhí)行是按照隊列順序(也就是go調(diào)用的順序)執(zhí)行的昧辽。(這個地方是不是覺得很奇怪衙熔??)

對于上面的第2-3步搅荞,創(chuàng)建一個M红氯,其過程:

  • 先找到一個空閑的P,如果沒有則直接返回咕痛,(哈哈脖隶,這個地方就保證了進(jìn)程不會占用超過自己設(shè)定的cpu個數(shù))
  • 調(diào)用系統(tǒng)api創(chuàng)建線程,不同的操作系統(tǒng)暇检,調(diào)用不一樣,其實就是和c語言創(chuàng)建過程是一致的婉称,(windows用的是CreateThread块仆,linux用的是clone系統(tǒng)調(diào)用)
  • 然后創(chuàng)建的這個線程里面才是真正做事的,循環(huán)執(zhí)行G任務(wù)

那就會有個問題王暗,如果一個系統(tǒng)調(diào)用或者G任務(wù)執(zhí)行太長悔据,他就會一直占用這個線程,由于本地隊列的G任務(wù)是順序執(zhí)行的俗壹,其它G任務(wù)就會阻塞了科汗,怎樣中止長任務(wù)的呢?

這樣滴绷雏,啟動的時候头滔,會專門創(chuàng)建一個線程sysmon,用來監(jiān)控和管理涎显,在內(nèi)部是一個循環(huán):

  1. 記錄所有P的G任務(wù)計數(shù)schedtick坤检,(schedtick會在每執(zhí)行一個G任務(wù)后遞增)
  2. 如果檢查到 schedtick一直沒有遞增,說明這個P一直在執(zhí)行同一個G任務(wù)期吓,如果超過一定的時間(10ms)早歇,就在這個G任務(wù)的棧信息里面加一個標(biāo)記
  3. 然后這個G任務(wù)在執(zhí)行的時候,如果遇到非內(nèi)聯(lián)函數(shù)調(diào)用,就會檢查一次這個標(biāo)記箭跳,然后中斷自己晨另,把自己加到隊列末尾,執(zhí)行下一個G
  4. 如果沒有遇到非內(nèi)聯(lián)函數(shù)(有時候正常的小函數(shù)會被優(yōu)化成內(nèi)聯(lián)函數(shù))調(diào)用的話谱姓,那就慘了借尿,會一直執(zhí)行這個G任務(wù),直到它自己結(jié)束逝段;如果是個死循環(huán)垛玻,并且GOMAXPROCS=1的話,恭喜你奶躯,夯住了帚桩!親測,的確如此

對于一個G任務(wù)嘹黔,中斷后的恢復(fù)過程:

  • 中斷的時候?qū)⒓拇嫫骼锏臈P畔⒄撕浚4娴阶约旱腉對象里面
  • 當(dāng)再次輪到自己執(zhí)行時,將自己保存的棧信息復(fù)制到寄存器里面儡蔓,這樣就接著上次之后運(yùn)行了郭蕉。

但是還有一個問題,就是系統(tǒng)啟動的過程

  1. 系統(tǒng)啟動的時候喂江,首先跑的是主線程召锈,那第一個M應(yīng)該就是主線程吧(按照C語言的理解,嘿嘿)获询,這里叫M1涨岁,可以看前面的圖
  2. 然后這個主線程會綁定第一個P1
  3. 咱們寫的main函數(shù),其實是作為一個goroutine來執(zhí)行的
  4. 也就是第一個P1就有了一個G1任務(wù)吉嚣,然后第一個M1就執(zhí)行這個G1任務(wù)(也就是main函數(shù))梢薪,創(chuàng)建這個G1的時候不用創(chuàng)建M了,因為已經(jīng)有了M1
  5. 這個main函數(shù)里面所有的goroutine尝哆,都綁定到當(dāng)前的M1所對應(yīng)的P1上
  6. 然后創(chuàng)建main里的goroutine的時候(比如G2)秉撇,就會創(chuàng)建新的M2,新的M2里的初始P2的本地任務(wù)隊列是空的秋泄,會從P1里面取一些過來琐馆,哈哈
  7. 這樣兩個M1,M2各自執(zhí)行自己的G任務(wù)印衔,再依次往復(fù)啡捶,這下就圓滿了

綜上:
所以goroutine是按照搶占式調(diào)度的,一個goroutine最多執(zhí)行10ms就會換作下一個
這個和目前主流系統(tǒng)的的cpu調(diào)度類似(按照時間分片)

windows:20ms

linux:5ms-800ms

注意:
在Golang中編譯器也會嘗試進(jìn)行內(nèi)聯(lián)奸焙,將小函數(shù)直接復(fù)制并編譯瞎暑,為了內(nèi)聯(lián)彤敛,盡量消除編譯器無法偵測的dead code,利用gobuild -gcflags=-m編譯命令可以查看程序內(nèi)聯(lián)狀態(tài)了赌,不得不說golang的編譯工具鏈還是很強(qiáng)大的墨榄,十分有利于程序的優(yōu)化。

如果有任何疑問勿她,歡迎提出袄秩,


作者:正版兩只羊
原文:https://blog.csdn.net/liangzhiyang/article/details/52669851

添加小編微信:grey0805,加入知識學(xué)習(xí)小分隊~逢并!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末之剧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子砍聊,更是在濱河造成了極大的恐慌背稼,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玻蝌,死亡現(xiàn)場離奇詭異蟹肘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)俯树,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門帘腹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人许饿,你說我怎么就攤上這事阳欲。” “怎么了陋率?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵胸完,是天一觀的道長。 經(jīng)常有香客問我翘贮,道長,這世上最難降的妖魔是什么爆惧? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任狸页,我火速辦了婚禮,結(jié)果婚禮上扯再,老公的妹妹穿的比我還像新娘芍耘。我一直安慰自己,他們只是感情好熄阻,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布斋竞。 她就那樣靜靜地躺著,像睡著了一般秃殉。 火紅的嫁衣襯著肌膚如雪坝初。 梳的紋絲不亂的頭發(fā)上浸剩,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機(jī)與錄音鳄袍,去河邊找鬼绢要。 笑死,一個胖子當(dāng)著我的面吹牛拗小,可吹牛的內(nèi)容都是我干的重罪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哀九,長吁一口氣:“原來是場噩夢啊……” “哼剿配!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阅束,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤呼胚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后围俘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砸讳,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年界牡,在試婚紗的時候發(fā)現(xiàn)自己被綠了簿寂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡宿亡,死狀恐怖常遂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挽荠,我是刑警寧澤克胳,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站圈匆,受9級特大地震影響漠另,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跃赚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一笆搓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纬傲,春花似錦满败、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至汁雷,卻和暖如春净嘀,著一層夾襖步出監(jiān)牢的瞬間报咳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工面粮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留少孝,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓熬苍,卻偏偏與公主長得像稍走,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子柴底,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容