(譯)Go 語言的工作竊取調(diào)度器

原文鏈接:Go's work-stealing scheduler

Go 調(diào)度程序的任務(wù)是在多個運行在一個或多個處理器上的系統(tǒng)線程上分發(fā)出可運行的 goroutine昨寞。在多線程計算中,調(diào)度已經(jīng)出現(xiàn)了兩種模式:工作共享與工作竊取腋腮。

  • 工作共享:當一個處理器創(chuàng)建新的線程時,它試圖將一部分線程遷移到其他的處理器上執(zhí)行,期望更充分的利用那些 IDLE 狀態(tài)的處理器煮剧。
  • 工作竊瑞惺辍:未被充分利用的處理器會主動尋找其他處理器上的線程,并“竊取”一些線程猾瘸。

與工作共享模式相比界赔,工作竊取模式線程的遷移發(fā)生的頻率更低。當所有的處理器都有工作要運行時牵触,沒有任何線程被遷移淮悼。一旦有了空閑處理器,就會考慮遷移揽思。

Go 從 1.1 版本開始就有了一個工作竊取模式的調(diào)度程序袜腥,它是由 Dmitry Vyukov 貢獻的。這篇文章將深入地解釋什么是工作竊取的調(diào)度程序钉汗,以及如何實現(xiàn)一個羹令。

調(diào)度的基礎(chǔ)

Go有一個 M:N 的調(diào)度程序鲤屡,它可以使用多核處理器。在任何時候福侈,M 個 goroutine 都需要被分發(fā)在最多 GOMAXPROCS 個處理器上運行的 N 個系統(tǒng)線程上酒来。Go調(diào)度程序使用以下術(shù)語來描述 goroutines、線程和處理器:

  1. G:goroutine
  2. M:系統(tǒng)線程(Machine)
  3. P:處理器

有一個特定于處理器的本地 goroutine 隊列和一個全局的 goroutine 隊列肪凛。每個系統(tǒng)線程都應(yīng)該被分配給一個處理器堰汉,如果處理器被阻塞或被系統(tǒng)調(diào)用,那么可能處理器上會沒有線程伟墙。在任何時候翘鸭,最多有
GOMAXPROCS 個處理器被用于分配。任何時候远荠,一個線程都只能運行在一個處理器上矮固。如果有需要調(diào)度器也可以創(chuàng)建更多的線程。

  • image.png

每一輪的調(diào)度都只是找到一個可運行的 goroutine 并執(zhí)行它譬淳。在每一輪的調(diào)度中档址,搜索都按照以下順序進行:

runtime.schedule() {
    // only 1/61 of the time, check the global runnable queue for a G.
    // if not found, check the local queue.
    // if not found,
    //     try to steal from other Ps.
    //     if not, check the global runnable queue.
    //     if not found, poll network.
}

一旦找到一個可運行的 goroutine ,它就會被執(zhí)行邻梆,直到被阻塞守伸。

注意:看起來全局隊列比局部隊列優(yōu)先級更高,但是偶爾檢查全局隊列只是為了避免系統(tǒng)線程在局部隊列中的 goroutine 用盡前只調(diào)用局部 goroutine 隊列中的 goroutine浦妄。

竊取

當一個 goroutine 被創(chuàng)建或一個已經(jīng)存在的 goroutine 變?yōu)榭梢赃\行狀態(tài)尼摹,它被推送到當前處理器上的一個可運行的 goroutines 隊列中,當處理器執(zhí)行完一個 goroutine剂娄,它將試圖從自己的局部可運行 goroutine 隊列中彈出這個 goroutine蠢涝。如果隊列為空,處理器會隨機選擇一個其他處理器阅懦,并試圖從這個處理器的局部可運行 goroutine 隊列中偷取一半數(shù)量的可運行 goroutine和二。

  • image.png

在上面的例子中,P2 這個處理器無法找到任何可執(zhí)行的 goroutines耳胎。因此惯吕,它隨機選擇另一個處理器 P1,并將 3 個 goroutines 偷到自己的局部隊列中怕午。P2 將執(zhí)行這些 goroutines废登,而調(diào)度器也將在多個處理器之間更均衡的調(diào)度。

旋轉(zhuǎn)線程

調(diào)度程序總是希望將可運行的 goroutines 分發(fā)到線程中郁惜,以便充分利用處理器堡距,但同時我們又需要限制過多的任務(wù)來節(jié)省 CPU 資源。與此相矛盾的是,調(diào)度器還需要能夠擴展到高吞吐量和CPU密集的程序中吏颖。

如果性能很關(guān)鍵搔体,那么經(jīng)常性的搶占將顯得十分的昂貴,并且對高吞吐量的程序來說這也是個嚴重的問題半醉。操作系統(tǒng)線程之間不應(yīng)該頻繁的傳遞可運行的 goroutine疚俱,因為這將導(dǎo)致延遲的增加。另外缩多,在有系統(tǒng)調(diào)用的情況下呆奕,系統(tǒng)線程需要不斷的 block 與 unblock,這也是非常昂貴的同時也增加了很多額外的開銷衬吆。

為了減少線程間傳遞梁钾,調(diào)度器實現(xiàn)了“旋轉(zhuǎn)線程”。旋轉(zhuǎn)線程雖然消耗了額外的 CPU 資源逊抡,但是它們最小化了操作系統(tǒng)線程的搶占姆泻。一個線程正在旋轉(zhuǎn),如果:

  1. 一個擁有線程的處理器正在尋找一個可執(zhí)行的 goroutine冒嫡。
  2. 一個沒有所屬處理器的線程正在尋找一個可以依附的處理器
  3. 當它準備一個 goroutine 時拇勃,如果有一個空閑的處理器并且沒有其他的旋轉(zhuǎn)線程,調(diào)度程序會取消一個額外的線程孝凌,然后旋轉(zhuǎn)這個線程方咆。

在任何時候,都有最多 GOMAXPROCS 個線程在旋轉(zhuǎn)蟀架。當一個旋轉(zhuǎn)的線程找到工作后瓣赂,它就會脫離自旋狀態(tài)。

如果空閑的線程沒有處理器可分配片拍,則已分配到處理器上的空閑線程不會阻塞煌集。當新的 goroutine 被創(chuàng)建或者一個線程被阻塞時,調(diào)度程序?qū)⒋_保至少有一個旋轉(zhuǎn)的線程捌省,這確保了當沒有可運行的 goroutine 時程序仍可以運行牙勘,也避免過多的線程 block/unblock。

Go調(diào)度程序做了很多工作所禀,以避免對操作系統(tǒng)線程的過度搶占,通過將它們調(diào)度到正確的和未充分利用的處理器上放钦,并實現(xiàn)了“旋轉(zhuǎn)”線程色徘,以避免出現(xiàn)阻塞/未阻塞的轉(zhuǎn)換。
調(diào)度事件可以通過執(zhí)行跟蹤程序跟蹤操禀。如果你認為你的處理器利用率很低褂策,那么你可以排查一下正在發(fā)生什么。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市斤寂,隨后出現(xiàn)的幾起案子耿焊,更是在濱河造成了極大的恐慌,老刑警劉巖遍搞,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罗侯,死亡現(xiàn)場離奇詭異,居然都是意外死亡溪猿,警方通過查閱死者的電腦和手機钩杰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诊县,“玉大人讲弄,你說我怎么就攤上這事∫廊” “怎么了避除?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長胸嘁。 經(jīng)常有香客問我瓶摆,道長,這世上最難降的妖魔是什么缴渊? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任赏壹,我火速辦了婚禮,結(jié)果婚禮上衔沼,老公的妹妹穿的比我還像新娘蝌借。我一直安慰自己,他們只是感情好指蚁,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布菩佑。 她就那樣靜靜地躺著,像睡著了一般凝化。 火紅的嫁衣襯著肌膚如雪稍坯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天搓劫,我揣著相機與錄音瞧哟,去河邊找鬼。 笑死枪向,一個胖子當著我的面吹牛勤揩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秘蛔,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼陨亡,長吁一口氣:“原來是場噩夢啊……” “哼傍衡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起负蠕,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蛙埂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后遮糖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绣的,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年止吁,在試婚紗的時候發(fā)現(xiàn)自己被綠了被辑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡敬惦,死狀恐怖盼理,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情俄删,我是刑警寧澤宏怔,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站畴椰,受9級特大地震影響臊诊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜斜脂,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一抓艳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帚戳,春花似錦玷或、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至对供,卻和暖如春位他,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背产场。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工鹅髓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人京景。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓迈勋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親醋粟。 傳聞我的和親對象是個殘疾皇子靡菇,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

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

  • Goroutine是Go里的一種輕量級線程——協(xié)程。相對線程米愿,協(xié)程的優(yōu)勢就在于它非常輕量級厦凤,進行上下文切換的代價非...
    witchiman閱讀 4,813評論 0 9
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)育苟,斷路器较鼓,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • http://skoo.me/go/2013/11/29/golang-schedule?hmsr=studygo...
    baboon閱讀 2,247評論 0 3
  • GCD調(diào)度隊列是執(zhí)行任務(wù)的強大工具。調(diào)度隊列允許您相對于調(diào)度者異步或者同步的執(zhí)行任意代碼塊违柏。您能夠使用調(diào)度隊列來執(zhí)...
    坤坤同學(xué)閱讀 6,661評論 1 3
  • 我的PAT系列文章更新重心已移至Github博烂,歡迎來看PAT題解的小伙伴請到Github Pages瀏覽最新內(nèi)容。...
    OliverLew閱讀 414評論 0 0