說在前面
Golang作為Google親自孵化出來一門現(xiàn)代編程語言种樱,可以說是吸收了眾多早期編程語言的優(yōu)點,又有其自己獨特的設(shè)計哲學俊卤。由于其簡潔的編程風格和優(yōu)秀的并發(fā)編程效率嫩挤,越來越多精通C++和Java的同學把Go作為自己第二,甚至是第一語言消恍。本文打算從Go調(diào)度器(Go Scheduler)的角度討論下Go的并發(fā)編程岂昭。
正文
什么是并行(Parallel)?
在同一時刻狠怨,多件事情一起做约啊。
什么叫并發(fā)處理(Concorrent)?
在一個時段內(nèi)佣赖,多件事情一起做恰矩。
舉個例子就是火影忍者中的鳴人影分身后產(chǎn)生的兩個鳴人是并行,本質(zhì)上產(chǎn)生了兩個獨立的鳴人茵汰;而七龍珠中孫悟空通過超高速移動產(chǎn)生兩個殘影是并發(fā)枢里,本質(zhì)上悟空還是只有一個孽鸡,只是本尊以超高速移動將時間片分配在兩個影子上蹂午。
并行和并發(fā)怎么體現(xiàn)在計算機中?
先談?wù)劜l(fā)彬碱,在計算機還是單處理器的時候豆胸,如果要同時運行兩個程序A和B,計算機將CPU的時間切成非常細小的片巷疼,這一個時間片去執(zhí)行程序A晚胡,第二個時間片去執(zhí)行程序B,只要時間片切換得非常快估盘,對于使用計算機的人來說A和B像是在同時運行瓷患,但在同一個時間片內(nèi)部,CPU只能處理程序A或者程序B遣妥。
再聊聊并發(fā)擅编,人們發(fā)現(xiàn)單處理器的時鐘頻率很難提升,如果同時運行100個程序箫踩,由于切換速度不夠快爱态,每個程序分到時間片的頻率太低,表現(xiàn)上來看每一個程序都會變慢境钟。既然處理器太少了锦担,那么,就多加幾個處理器慨削,100個任務(wù)就最多有n個同時在運行洞渔,使用者會感覺到程序變快。
現(xiàn)代計算機理盆,n個線程可以依附在n個獨立的CPU核心上同時(并行)計算痘煤。但是CPU核心非常貴,所以常見的計算機也就4-32核猿规。
Golang沒有設(shè)置線程數(shù)量的API衷快,調(diào)度器在并發(fā)編程上是怎么設(shè)計的?
Go調(diào)度器引入了新的并發(fā)單位——協(xié)程(goroutine)
Go底層的執(zhí)行還是依賴于內(nèi)核級的線程姨俩,但是Go程序中并發(fā)單元的調(diào)度蘸拔,都由調(diào)度器來調(diào)度,顯然环葵,底層需要開多少個線程调窍,也是Go調(diào)度器基于某些策略動態(tài)決定的。具體是什么樣的策略张遭,后續(xù)會聊到邓萨。
所以,Go程序本質(zhì)上的性能的好壞菊卷,與Go調(diào)度器的策略算法有非常大的關(guān)系缔恳。既要避免線程開太多,頻繁上下文切換消耗時間洁闰。也要避免線程數(shù)量不夠歉甚,導致無法充分利用多核優(yōu)勢。
協(xié)程與線程有怎么樣的關(guān)系扑眉?
M: Machine纸泄,可以簡單理解為內(nèi)核級線程赖钞,M與線程數(shù)量1:1
G: Goroutine,協(xié)程
P: Processor聘裁,處理器雪营,每個P協(xié)調(diào)n個G在某一個M上執(zhí)行『獗悖可以通過GOMAXPROCS設(shè)置P的個數(shù)卓缰。GOMAXPROCS表示最多有多少個G可以并行。
協(xié)程的阻塞有哪些情況砰诵?
Gwaitting. 內(nèi)部channel或者mutex阻塞
Gsyscall. 調(diào)用了syscall(沒有事件準備的Nonblocking IO除外)
G處于Gruning狀態(tài)征唬,調(diào)度器會怎么處理其它待執(zhí)行的G?
時間片到了茁彭,自然會出讓線程資源
G如果因為Gwaitting而阻塞了总寒,調(diào)度器會怎么處理其它待執(zhí)行的G?
G阻塞后理肺,立刻把執(zhí)行權(quán)給隊首的G
G如果因為Gsyscall而阻塞了摄闸,調(diào)度器會怎么處理其它待執(zhí)行的G?
調(diào)度器斷開阻塞的M和當前P之間的關(guān)聯(lián)妹萨,找到新創(chuàng)建的M年枕,將P與之建立聯(lián)系,從P中可運行G列表取出新的G乎完,放在新的M中執(zhí)行熏兄。
分成兩種情況
沒有空閑的M。
如果這個時候可運行的G的隊列特別長树姨,所有的M都因為Gsyscall阻塞了摩桶,調(diào)度器為了防止系統(tǒng)整個無法工作,將創(chuàng)建與G同等數(shù)量的線程帽揪。有空閑的M
由于在第一種情況下硝清,會產(chǎn)生很多線程,當G的任務(wù)執(zhí)行完后转晰,這些線程(Thread-M)就空閑下來了芦拿。
結(jié)合以上描述,
一個線程什么時候獲得CPU時間查邢,能夠運行多久蔗崎,是由OS線程調(diào)度器根據(jù)某種調(diào)度策略所定。這個是線程調(diào)度器侠坎。
類似得蚁趁,
一個協(xié)程什么時候獲得線程的時間裙盾,能夠占用線程運行多久实胸,就是Go調(diào)度器根據(jù)某種調(diào)度策略所定他嫡。這個是Go調(diào)度器。
說在后面
如果喜歡本文庐完,請收藏后點個贊钢属,咱們江湖再見。