【go語言學(xué)習(xí)】并發(fā)概念

一哄陶、并發(fā)性Concurrency

1帆阳、多任務(wù)

多任務(wù)是操作系統(tǒng)可以同時執(zhí)行多個任務(wù)。如屋吨,可以一邊聽音樂蜒谤,一邊刷微博,一邊聊QQ至扰,還能同時開微信鳍徽。這就是多任務(wù)同時運(yùn)行。

2敢课、線程process與進(jìn)程thread阶祭、協(xié)程coroutine

進(jìn)程是一個程序在一個數(shù)據(jù)集中的一次動態(tài)執(zhí)行過程绷杜,可以簡單理解為“正在執(zhí)行的程序”,它是CPU資源分配和調(diào)度的獨(dú)立單位濒募。

線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位接剩。它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位萨咳。一條線程指的是進(jìn)程中一個單一順序的控制流,一個進(jìn)程中可以并發(fā)多個線程疫稿,每條線程并行執(zhí)行不同的任務(wù)培他。

簡單來說:

進(jìn)程:指在系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序;程序一旦運(yùn)行就是進(jìn)程遗座;進(jìn)程——資源分配的最小單位舀凛。
線程:系統(tǒng)分配處理器時間資源的基本單元,或者說進(jìn)程之內(nèi)獨(dú)立執(zhí)行的一個單元執(zhí)行流途蒋。線程——程序執(zhí)行的最小單位猛遍。

進(jìn)程的局限是創(chuàng)建、撤銷和切換的開銷比較大号坡。
線程的優(yōu)點(diǎn)是減小了程序并發(fā)執(zhí)行時的開銷懊烤,提高了操作系統(tǒng)的并發(fā)性能,缺點(diǎn)是線程沒有自己的系統(tǒng)資源宽堆,只擁有在運(yùn)行時必不可少的資源腌紧,但同一進(jìn)程的各線程可以共享進(jìn)程所擁有的系統(tǒng)資源。

操作系統(tǒng)的設(shè)計畜隶,因此可以歸結(jié)為三點(diǎn):

  • (1)以多進(jìn)程形式壁肋,允許多個任務(wù)同時運(yùn)行;
  • (2)以多線程形式籽慢,允許單個任務(wù)分成不同的部分運(yùn)行浸遗;
  • (3)提供協(xié)調(diào)機(jī)制,一方面防止進(jìn)程之間和線程之間產(chǎn)生沖突箱亿,另一方面允許進(jìn)程之間和線程之間共享資源跛锌。

協(xié)程coroutine是一種用戶態(tài)的輕量級線程,又稱微線程届惋,協(xié)程的調(diào)度完全由用戶控制察净。人們通常將協(xié)程和子程序(函數(shù))比較著理解。 子程序調(diào)用總是一個入口盼樟,一次返回氢卡,一旦退出即完成了子程序的執(zhí)行。

與傳統(tǒng)的系統(tǒng)級線程和進(jìn)程相比晨缴,協(xié)程的最大優(yōu)勢在于其"輕量級"译秦,可以輕松創(chuàng)建上百萬個而不會導(dǎo)致系統(tǒng)資源衰竭,而線程和進(jìn)程通常最多也不能超過1萬的。這也是協(xié)程也叫輕量級線程的原因筑悴。

Go語言對于并發(fā)的實(shí)現(xiàn)是靠協(xié)程们拙,coroutine

3、并行與并發(fā)

并行與并發(fā)(Concurrency and Parallelism)是兩個不同的概念阁吝,理解它們對于理解多線程模型非常重要砚婆。
在描述程序的并發(fā)或者并行時,應(yīng)該說明從進(jìn)程或者線程的角度出發(fā)突勇。

  • 并發(fā):一個時間段內(nèi)有很多的線程或進(jìn)程在執(zhí)行装盯,但任何時間點(diǎn)上都只有一個在執(zhí)行,多個線程或進(jìn)程爭搶時間片輪流執(zhí)行
  • 并行:一個時間段和時間點(diǎn)上都有多個線程或進(jìn)程在執(zhí)行

并行需要硬件支持甲馋,單核處理器只能是并發(fā)埂奈,多核處理器才能做到并行執(zhí)行。

  • 并發(fā)是并行的必要條件定躏,如果一個程序本身就不是并發(fā)的账磺,也就是只有一個邏輯執(zhí)行順序,那么我們不可能讓其被并行處理痊远。
  • 并發(fā)不是并行的充分條件垮抗,一個并發(fā)的程序,如果只被一個CPU進(jìn)行處理(通過分時)碧聪,那么它就不是并行的借宵。

舉例:
如果我們在瀏覽web頁面時,下載文件和呈現(xiàn)頁面是周期交替執(zhí)行的矾削,這就是并發(fā)壤玫。
如果是運(yùn)行在多核CPU上,下載文件和呈現(xiàn)頁面可能同時在不同的內(nèi)核中運(yùn)行哼凯。這就是所謂的并行性欲间。


并行性Parallelism不會總是導(dǎo)致更快的執(zhí)行時間,因為并行運(yùn)行的組件可能需要相互通信断部,這種通信開銷很高猎贴,因此,并行程序并不總是導(dǎo)致更快的執(zhí)行時間!

二蝴光、幾種不同的多線程模型

線程的實(shí)現(xiàn)可以分為兩類:

  • 用戶級線程(User-LevelThread, ULT):用戶線程由用戶代碼支持她渴。
  • 內(nèi)核級線程(Kemel-LevelThread, KLT):內(nèi)核線程由操作系統(tǒng)內(nèi)核支持。

多線程模型:
多線程模型即用戶級線程和內(nèi)核級線程的不同連接方式蔑祟。

1趁耗、【用戶級線程模型】多對一模型(M : 1)

將多個用戶級線程映射到一個內(nèi)核級線程,線程管理在用戶空間完成疆虚。 此模式中苛败,用戶級線程對操作系統(tǒng)不可見(即透明)满葛。

優(yōu)點(diǎn): 這種模型的好處是線程上下文切換都發(fā)生在用戶空間,避免的模態(tài)切換(mode switch)罢屈,從而對于性能有積極的影響嘀韧。

缺點(diǎn):所有的線程基于一個內(nèi)核調(diào)度實(shí)體即內(nèi)核線程,這意味著只有一個處理器可以被利用缠捌,在多處理器環(huán)境下這是不能夠被接受的锄贷,本質(zhì)上,用戶線程只解決了并發(fā)問題曼月,但是沒有解決并行問題谊却。如果線程因為 I/O 操作陷入了內(nèi)核態(tài),內(nèi)核態(tài)線程阻塞等待 I/O 數(shù)據(jù)十嘿,則所有的線程都將會被阻塞,用戶空間也可以使用非阻塞而 I/O岳锁,但是不能避免性能及復(fù)雜度問題绩衷。

2、【內(nèi)核級線程模型】一對一模型(1 : 1)

將每個用戶級線程映射到一個內(nèi)核級線程激率。


每個線程由內(nèi)核調(diào)度器獨(dú)立的調(diào)度咳燕,所以如果一個線程阻塞則不影響其他的線程。

優(yōu)點(diǎn):在多核處理器的硬件的支持下乒躺,內(nèi)核空間線程模型支持了真正的并行招盲,當(dāng)一個線程被阻塞后,允許另一個線程繼續(xù)執(zhí)行嘉冒,所以并發(fā)能力較強(qiáng)曹货。

缺點(diǎn):每創(chuàng)建一個用戶級線程都需要創(chuàng)建一個內(nèi)核級線程與其對應(yīng),這樣創(chuàng)建線程的開銷比較大讳推,會影響到應(yīng)用程序的性能顶籽。

3、【兩級線程模型】多對多模型(M : N)

內(nèi)核線程和用戶線程的數(shù)量比為 M : N银觅,內(nèi)核用戶空間綜合了前兩種的優(yōu)點(diǎn)礼饱。

這種模型需要內(nèi)核線程調(diào)度器和用戶空間線程調(diào)度器相互操作,本質(zhì)上是多個線程被綁定到了多個內(nèi)核線程上究驴,這使得大部分的線程上下文切換都發(fā)生在用戶空間镊绪,而多個內(nèi)核線程又可以充分利用處理器資源。

三洒忧、goroutine機(jī)制的調(diào)度實(shí)現(xiàn)

goroutine機(jī)制實(shí)現(xiàn)了M : N的線程模型蝴韭,goroutine機(jī)制是協(xié)程(coroutine)的一種實(shí)現(xiàn),golang內(nèi)置的調(diào)度器熙侍,可以讓多核CPU中每個CPU執(zhí)行一個協(xié)程万皿。

理解goroutine機(jī)制的原理摧找,關(guān)鍵是理解Go語言調(diào)度器scheduler的實(shí)現(xiàn)。

1牢硅、調(diào)度器是如何工作的

Go語言中支撐整個scheduler實(shí)現(xiàn)的主要有4個重要結(jié)構(gòu)蹬耘,分別是M、G减余、P综苔、Sched, 前三個定義在runtime.h中位岔,Sched定義在proc.c中如筛。

Sched是調(diào)度器,它維護(hù)有存儲M和G的隊列以及調(diào)度器的一些狀態(tài)信息等抒抬。

M是Machine杨刨,系統(tǒng)線程,它由操作系統(tǒng)管理的擦剑,goroutine就是跑在M之上的妖胀;M是一個很大的結(jié)構(gòu),里面維護(hù)小對象內(nèi)存cache(mcache)惠勒、當(dāng)前執(zhí)行的goroutine赚抡、隨機(jī)數(shù)發(fā)生器等等非常多的信息。M的作用就是執(zhí)行G中包裝的并發(fā)任務(wù)纠屋。Go運(yùn)行時系統(tǒng)中的調(diào)度器的主要職責(zé)就是將G公平合理的安排到多個M上去執(zhí)行涂臣。

P是Processor,邏輯處理器售担,它的主要用途就是用來執(zhí)行g(shù)oroutine的赁遗,它維護(hù)了一個goroutine隊列,即runqueue族铆,并為G在M上的運(yùn)行提供本地化資源吼和。。Processor是讓我們從N:1調(diào)度到M:N調(diào)度的重要部分骑素。

G是goroutine炫乓,用go關(guān)鍵字加函數(shù)調(diào)用的代碼就是創(chuàng)建了一個G對象,是對一個要并發(fā)執(zhí)行的任務(wù)的封裝献丑,也可以稱作用戶態(tài)線程末捣。屬于用戶級資源,對OS透明创橄,具備輕量級箩做,可以大量創(chuàng)建,上下文切換成本低等特點(diǎn)妥畏。

Processor的數(shù)量是在啟動時被設(shè)置為環(huán)境變量GOMAXPROCS的值邦邦,或者通過運(yùn)行時調(diào)用函數(shù)GOMAXPROCS()進(jìn)行設(shè)置安吁。Processor數(shù)量固定意味著任意時刻只有GOMAXPROCS個線程在運(yùn)行g(shù)o代碼。

我們分別用三角形燃辖,矩形和圓形表示Machine Processor和Goroutine鬼店。


在單核處理器的場景下,所有g(shù)oroutine運(yùn)行在同一個M系統(tǒng)線程中黔龟,每一個M系統(tǒng)線程維護(hù)一個Processor妇智,任何時刻,一個Processor中只有一個goroutine氏身,其他goroutine在runqueue中等待巍棱。一個goroutine運(yùn)行完自己的時間片后,讓出上下文蛋欣,回到runqueue中航徙。 多核處理器的場景下,為了運(yùn)行g(shù)oroutines陷虎,每個M系統(tǒng)線程會持有一個Processor到踏。

在正常情況下,scheduler會按照上面的流程進(jìn)行調(diào)度泻红,但是線程會發(fā)生阻塞等情況夭禽,看一下goroutine對線程阻塞等的處理霞掺。

2谊路、線程阻塞

當(dāng)正在運(yùn)行的goroutine阻塞的時候,例如進(jìn)行系統(tǒng)調(diào)用菩彬,會再創(chuàng)建一個系統(tǒng)線程(M1)缠劝,當(dāng)前的M線程放棄了它的Processor,P轉(zhuǎn)到新的線程中去運(yùn)行骗灶。

3惨恭、runqueue執(zhí)行完成

當(dāng)其中一個Processor的runqueue為空,沒有g(shù)oroutine可以調(diào)度耙旦。它會從另外一個上下文偷取一半的goroutine脱羡。

Go運(yùn)行時系統(tǒng)通過構(gòu)造G-P-M對象模型實(shí)現(xiàn)了一套用戶態(tài)的并發(fā)調(diào)度系統(tǒng),可以自己管理和調(diào)度自己的并發(fā)任務(wù)免都,所以可以說Go語言原生支持并發(fā)锉罐。自己實(shí)現(xiàn)的調(diào)度器負(fù)責(zé)將并發(fā)任務(wù)分配到不同的內(nèi)核線程上運(yùn)行,然后內(nèi)核調(diào)度器接管內(nèi)核線程在CPU上的執(zhí)行與調(diào)度绕娘。

可以看到Go的并發(fā)用起來非常簡單脓规,用了一個語法糖將內(nèi)部復(fù)雜的實(shí)現(xiàn)結(jié)結(jié)實(shí)實(shí)的包裝了起來。其內(nèi)部可以用下面這張圖來概述:

參考文章:
https://zhuanlan.zhihu.com/p/77206570
https://www.cnblogs.com/williamjie/p/9456764.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末险领,一起剝皮案震驚了整個濱河市侨舆,隨后出現(xiàn)的幾起案子秒紧,更是在濱河造成了極大的恐慌,老刑警劉巖挨下,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熔恢,死亡現(xiàn)場離奇詭異,居然都是意外死亡复颈,警方通過查閱死者的電腦和手機(jī)绩聘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耗啦,“玉大人凿菩,你說我怎么就攤上這事≈慕玻” “怎么了衅谷?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長似将。 經(jīng)常有香客問我获黔,道長,這世上最難降的妖魔是什么在验? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任玷氏,我火速辦了婚禮,結(jié)果婚禮上腋舌,老公的妹妹穿的比我還像新娘盏触。我一直安慰自己,他們只是感情好块饺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布赞辩。 她就那樣靜靜地躺著,像睡著了一般授艰。 火紅的嫁衣襯著肌膚如雪辨嗽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天淮腾,我揣著相機(jī)與錄音糟需,去河邊找鬼。 笑死谷朝,一個胖子當(dāng)著我的面吹牛洲押,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播徘禁,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诅诱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了送朱?” 一聲冷哼從身側(cè)響起娘荡,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤干旁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后炮沐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體争群,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年大年,在試婚紗的時候發(fā)現(xiàn)自己被綠了换薄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡翔试,死狀恐怖轻要,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情垦缅,我是刑警寧澤冲泥,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站壁涎,受9級特大地震影響凡恍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怔球,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一嚼酝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧竟坛,春花似錦闽巩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽延刘。三九已至漫试,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碘赖,已是汗流浹背驾荣。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留普泡,地道東北人播掷。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像撼班,于是被迫代替她去往敵國和親歧匈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355