Golang并發(fā)調(diào)度模型解析

學(xué)習(xí)golang滔驶,必然繞不開并行與并發(fā)這樣的概念遇革,作為golang的一大賣點(diǎn),輕量級的協(xié)程應(yīng)該是我們要理解的揭糕,包括他的調(diào)度萝快。

而且,雖然golang的goroutine輕量級著角,方便大量創(chuàng)建揪漩,但是在高度并發(fā)的情況下,也會出現(xiàn)一些問題吏口。

Goroutine & Scheduler

首先奄容,通常我們會把golang的goroutine簡單的理解為coroutine(協(xié)程),但是實(shí)際上兩者是有差別的产徊,現(xiàn)在主流的線程模型分為3種:內(nèi)核級線程模型昂勒,用戶級線程模型,和兩級線程模型(也稱為混合線程模型)舟铜。

傳統(tǒng)的協(xié)程屬于用戶級線程模型戈盈,而goroutine和他的go scheduler在底層實(shí)現(xiàn)上實(shí)際上屬于兩級線程模型。

所以兩者實(shí)際是有區(qū)別的谆刨。

線程那些事兒

? 互聯(lián)網(wǎng)時代以降塘娶,由于在線用戶數(shù)量的爆炸归斤,單臺服務(wù)器處理的連接也水漲船高,迫使編程模式由從前的串行模式升級到并發(fā)模型血柳,而幾十年來官册,并發(fā)模型也是一代代地升級,有IO多路復(fù)用难捌、多進(jìn)程以及多線程膝宁,這幾種模型都各有長短,現(xiàn)代復(fù)雜的高并發(fā)架構(gòu)大多是幾種模型協(xié)同使用根吁,不同場景應(yīng)用不同模型员淫,揚(yáng)長避短,發(fā)揮服務(wù)器的最大性能击敌,而多線程介返,因?yàn)槠漭p量和易用,成為并發(fā)編程中使用頻率最高的并發(fā)模型沃斤,而后衍生的協(xié)程等其他子產(chǎn)品圣蝎,也都基于它,而我們今天要分析的 goroutine 也是基于線程衡瓶,因此徘公,我們先來聊聊線程的三大模型:

3種模型分別為:

內(nèi)核級線程模型,用戶級線程模型和兩級線程模型哮针,他們之間最大的區(qū)別就在于用戶線程與內(nèi)核調(diào)度實(shí)體(kernel Schedule Entry)的對應(yīng)關(guān)系上关面,而所謂的KSE其實(shí)就是指可以被操作系統(tǒng)內(nèi)核調(diào)度器調(diào)度的對象實(shí)體,其實(shí)就是內(nèi)核級線程十厢,是操作系統(tǒng)內(nèi)核的最小調(diào)度單元等太,也就是我們寫代碼時常說的線程。

Kernel Schedule Entry

首先蛮放,說一下缩抡,什么是KSE?

linux內(nèi)核中實(shí)際沒有線程的概念包颁,linux中的線程缝其,實(shí)際是一種輕量級的進(jìn)程,而進(jìn)程與線程都是KSE徘六。

用戶級線程

用戶級線程中,用戶線程與KSE是N對1的模式榴都,也就是說待锈,所有的用戶線程是在一個進(jìn)程中與一個KSE動態(tài)綁定的,而調(diào)度則都是通過用戶自己的調(diào)度器實(shí)現(xiàn)嘴高,比如說:python的gevent協(xié)程庫就是通過這種方式來實(shí)現(xiàn)的竿音。

而這種實(shí)現(xiàn)有什么好處呢和屎?

所有的行為都在用戶層面解決,CPU對于整個過程是無感的春瞬,避免了用戶態(tài)與內(nèi)核態(tài)來回切換導(dǎo)致的性能消耗柴信。

而他的缺點(diǎn)也很明顯:

其實(shí)這種方式?jīng)]法做到真正意義上的并發(fā):因?yàn)橛脩舻淖哉{(diào)度不存在cpu時鐘中斷和輪轉(zhuǎn)調(diào)度,所以宽气,如果一旦一個用戶線程得到了阻塞調(diào)用随常,所有的用戶線程都會被阻塞。

所以許多這樣實(shí)現(xiàn)的協(xié)程庫將阻塞的行為封裝成非阻塞的行為從而避免這樣的事情萄涯。

內(nèi)核級線程

內(nèi)核級線程中绪氛,用戶線程與KSE是一一對應(yīng)的。而且用戶線程的調(diào)度是交給cpu調(diào)度的涝影。

優(yōu)勢是實(shí)現(xiàn)簡單枣察,直接借助操作系統(tǒng)內(nèi)核的線程以及調(diào)度器,所以CPU可以快速切換調(diào)度線程燃逻,于是多個線程可以同時運(yùn)行序目,因此相較于用戶級線程模型它真正做到了并行處理;但它的劣勢是伯襟,由于直接借助了操作系統(tǒng)內(nèi)核來創(chuàng)建猿涨、銷毀和以及多個線程之間的上下文切換和調(diào)度,因此資源成本大幅上漲逗旁,且對性能影響很大嘿辟。

兩級線程模型

兩級線程模型中,用戶線程與KSE是N對M的關(guān)系片效。

兩級線程模型是根據(jù)前兩個模型綜合而來红伦,既不是完全依賴用戶自調(diào)度,也不是完全依賴cpu調(diào)度淀衣。

所有的用戶線程都會動態(tài)綁定到一個KSE上昙读,然后一旦這個KSE因?yàn)樽枞灰瞥鯿pu時,用戶線程可以繼續(xù)與其他的KSE綁定膨桥。

所以蛮浑,兩級線程模型的調(diào)度是一種中間態(tài)的調(diào)度。即:用戶調(diào)度器實(shí)現(xiàn)從用戶線程到KSE的調(diào)度只嚣,內(nèi)核調(diào)度器實(shí)現(xiàn)從KSE到CPU的調(diào)度沮稚。

G-P-M模型

一般的,對于一個OS線程來說册舞,都會有一個固定大小的內(nèi)存塊(2MB)來做棧儲存上下文信息蕴掏,2MB的大小就顯得十分不靈活,對于簡單的任務(wù),2MB太浪費(fèi)資源盛杰,但對于復(fù)雜的任務(wù)挽荡,2MB又太小了,于是goroutine自己實(shí)現(xiàn)了自己的線程即供。

每個goroutine都有自己的棧定拟,并且采取了動態(tài)擴(kuò)容的方法,初始僅分配2kb的大小逗嫡,并且不斷的動態(tài)擴(kuò)容青自,同時也會有GC來對棧的內(nèi)存進(jìn)行收縮。

任何用戶線程最終肯定都是要交由OS線程來執(zhí)行的祸穷,goroutine(稱為G)也不例外性穿,但是G并不直接綁定OS線程運(yùn)行,而是由Goroutine Scheduler中的 P - Logical Processor (邏輯處理器)來作為兩者的『中介』雷滚,P可以看作是一個抽象的資源或者一個上下文需曾,一個P綁定一個OS線程,在golang的實(shí)現(xiàn)里把OS線程抽象成一個數(shù)據(jù)結(jié)構(gòu):M祈远,G實(shí)際上是由M通過P來進(jìn)行調(diào)度運(yùn)行的呆万,但是在G的層面來看,P提供了G運(yùn)行所需的一切資源和環(huán)境车份,因此在G看來P就是運(yùn)行它的 “CPU”谋减,由 G、P扫沼、M 這三種由Go抽象出來的實(shí)現(xiàn)出爹,最終形成了Go調(diào)度器的基本結(jié)構(gòu):

  • G: 表示Goroutine,每個Goroutine對應(yīng)一個G結(jié)構(gòu)體缎除,G存儲Goroutine的運(yùn)行堆棧严就、狀態(tài)以及任務(wù)函數(shù),可重用器罐。G并非執(zhí)行體梢为,每個G需要綁定到P才能被調(diào)度執(zhí)行。
  • P: Processor轰坊,表示邏輯處理器铸董, 對G來說,P相當(dāng)于CPU核肴沫,G只有綁定到P(在P的local runq中)才能被調(diào)度粟害。對M來說,P提供了相關(guān)的執(zhí)行環(huán)境(Context)颤芬,如內(nèi)存分配狀態(tài)(mcache)我磁,任務(wù)隊(duì)列(G)等孽文,P的數(shù)量決定了系統(tǒng)內(nèi)最大可并行的G的數(shù)量(前提:物理CPU核數(shù) >= P的數(shù)量),P的數(shù)量由用戶設(shè)置的GOMAXPROCS決定夺艰,但是不論GOMAXPROCS設(shè)置為多大,P的數(shù)量最大為256沉衣。
  • M: Machine郁副,OS線程抽象,代表著真正執(zhí)行計(jì)算的資源豌习,在綁定有效的P后存谎,進(jìn)入schedule循環(huán);而schedule循環(huán)的機(jī)制大致是從Global隊(duì)列肥隆、P的Local隊(duì)列以及wait隊(duì)列中獲取G既荚,切換到G的執(zhí)行棧上并執(zhí)行G的函數(shù),調(diào)用goexit做清理工作并回到M栋艳,如此反復(fù)恰聘。M并不保留G狀態(tài),這是G可以跨M調(diào)度的基礎(chǔ)吸占,M的數(shù)量是不定的晴叨,由Go Runtime調(diào)整,為了防止創(chuàng)建過多OS線程導(dǎo)致系統(tǒng)調(diào)度不過來矾屯,目前默認(rèn)最大限制為10000個兼蕊。

G-P-M模型調(diào)度

Go調(diào)度器工作時會維護(hù)兩種用來保存G的任務(wù)隊(duì)列:一種是一個Global任務(wù)隊(duì)列,一種是每個P維護(hù)的Local任務(wù)隊(duì)列件蚕。

當(dāng)通過go關(guān)鍵字創(chuàng)建一個新的goroutine的時候孙技,它會優(yōu)先被放入P的本地隊(duì)列。為了運(yùn)行g(shù)oroutine排作,M需要持有(綁定)一個P牵啦,接著M會啟動一個OS線程,循環(huán)從P的本地隊(duì)列里取出一個goroutine并執(zhí)行纽绍。當(dāng)然還有上文提及的 work-stealing調(diào)度算法:當(dāng)M執(zhí)行完了當(dāng)前P的Local隊(duì)列里的所有G后蕾久,P也不會就這么在那躺尸啥都不干,它會先嘗試從Global隊(duì)列尋找G來執(zhí)行拌夏,如果Global隊(duì)列為空僧著,它會隨機(jī)挑選另外一個P,從它的隊(duì)列里中拿走一半的G到自己的隊(duì)列中執(zhí)行障簿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盹愚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子站故,更是在濱河造成了極大的恐慌皆怕,老刑警劉巖毅舆,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愈腾,居然都是意外死亡憋活,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門虱黄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悦即,“玉大人,你說我怎么就攤上這事橱乱」际幔” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵泳叠,是天一觀的道長作瞄。 經(jīng)常有香客問我,道長危纫,這世上最難降的妖魔是什么宗挥? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮叶摄,結(jié)果婚禮上属韧,老公的妹妹穿的比我還像新娘。我一直安慰自己蛤吓,他們只是感情好宵喂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著会傲,像睡著了一般锅棕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淌山,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天裸燎,我揣著相機(jī)與錄音,去河邊找鬼泼疑。 笑死德绿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的退渗。 我是一名探鬼主播移稳,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼会油!你這毒婦竟也來了个粱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤翻翩,失蹤者是張志新(化名)和其女友劉穎都许,沒想到半個月后稻薇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胶征,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年塞椎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睛低。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡忱屑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出暇昂,到底是詐尸還是另有隱情,我是刑警寧澤伴嗡,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布急波,位于F島的核電站,受9級特大地震影響瘪校,放射性物質(zhì)發(fā)生泄漏澄暮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一阱扬、第九天 我趴在偏房一處隱蔽的房頂上張望泣懊。 院中可真熱鬧,春花似錦麻惶、人聲如沸馍刮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卡啰。三九已至,卻和暖如春警没,著一層夾襖步出監(jiān)牢的瞬間匈辱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工杀迹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亡脸,地道東北人。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓树酪,卻偏偏與公主長得像浅碾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嗅回,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349

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