關(guān)于 Golang 協(xié)程調(diào)度

發(fā)布時間:2024-03-22
下面由golang教程欄目給大家介紹golang 協(xié)程調(diào)度 ,希望對需要的朋友有所幫助!
一、線程模型n:1模型,n個用戶空間線程在1個內(nèi)核空間線程上運行。優(yōu)勢是上下文切換非??斓菬o法利用多核系統(tǒng)的優(yōu)點。1:1模型,1個內(nèi)核空間線程運行一個用戶空間線程。這種充分利用了多核系統(tǒng)的優(yōu)勢但是上下文切換非常慢,因為每一次調(diào)度都會在用戶態(tài)和內(nèi)核態(tài)之間切換。(posix線程模型(pthread),java)m:n模型, 每個用戶線程對應(yīng)多個內(nèi)核空間線程,同時也可以一個內(nèi)核空間線程對應(yīng)多個用戶空間線程。go打算采用這種模型,使用任意個內(nèi)核模型管理任意個goroutine。這樣結(jié)合了以上兩種模型的優(yōu)點,但缺點就是調(diào)度的復(fù)雜性。
下面看看golang的協(xié)程調(diào)度
m:一個用戶空間線程,同時對應(yīng)一個內(nèi)核線程,類似posix pthreadp:代表運行的上下文環(huán)境, 也就是我們上一節(jié)實現(xiàn)的調(diào)度器,一個調(diào)度器也會對應(yīng)一個就緒隊列g(shù):goroutine,即協(xié)程二、調(diào)度模型簡介
groutine能擁有強大的并發(fā)實現(xiàn)是通過gpm調(diào)度模型實現(xiàn),下面就來解釋下goroutine的調(diào)度模型。
go的調(diào)度器內(nèi)部有三個重要的結(jié)構(gòu):m,p,g
m:m是對內(nèi)核級線程的封裝,數(shù)量對應(yīng)真實的cpu數(shù),一個m就是一個線程,goroutine就是跑在m之上的;m是一個很大的結(jié)構(gòu),里面維護小對象內(nèi)存cache(mcache)、當前執(zhí)行的goroutine、隨機數(shù)發(fā)生器等等非常多的信息
g:代表一個goroutine,它有自己的棧,instruction pointer和其他信息(正在等待的channel等等),用于調(diào)度。
p:p全稱是processor,處理器,它的主要用途就是用來執(zhí)行g(shù)oroutine的。每個processor對象都擁有一個lrq(local run queue),未分配的goroutine對象保存在grq(global run queue )中,等待分配給某一個p的lrq中,每個lrq里面包含若干個用戶創(chuàng)建的goroutine對象。
golang采用的是多線程模型,更詳細的說他是一個兩級線程模型,但它對系統(tǒng)線程(內(nèi)核級線程)進行了封裝,暴露了一個輕量級的協(xié)程goroutine(用戶級線程)供用戶使用,而用戶級線程到內(nèi)核級線程的調(diào)度由golang的runtime負責,調(diào)度邏輯對外透明。goroutine的優(yōu)勢在于上下文切換在完全用戶態(tài)進行,無需像線程一樣頻繁在用戶態(tài)與內(nèi)核態(tài)之間切換,節(jié)約了資源消耗。
調(diào)度實現(xiàn)
從上圖中看,有2個物理線程m,每一個m都擁有一個處理器p,每一個也都有一個正在運行的goroutine。
p的數(shù)量可以通過gomaxprocs()來設(shè)置,它其實也就代表了真正的并發(fā)度,即有多少個goroutine可以同時運行。
圖中灰色的那些goroutine并沒有運行,而是出于ready的就緒態(tài),正在等待被調(diào)度。p維護著這個隊列(稱之為runqueue),
go語言里,啟動一個goroutine很容易:go function 就行,所以每有一個go語句被執(zhí)行,runqueue隊列就在其末尾加入一個
goroutine,在下一個調(diào)度點,就從runqueue中取出(如何決定取哪個goroutine?)一個goroutine執(zhí)行。
當一個os線程m0陷入阻塞時(如下圖),p轉(zhuǎn)而在運行m1,圖中的m1可能是正被創(chuàng)建,或者從線程緩存中取出。
當mo返回時,它必須嘗試取得一個p來運行g(shù)oroutine,一般情況下,它會從其他的os線程那里拿一個p過來,
如果沒有拿到的話,它就把goroutine放在一個global
runqueue里,然后自己睡眠(放入線程緩存里)。所有的p也會周期性的檢查global
runqueue并運行其中的goroutine,否則global runqueue上的goroutine永遠無法執(zhí)行。
另一種情況是p所分配的任務(wù)g很快就執(zhí)行完了(分配不均),這就導(dǎo)致了這個處理器p很忙,但是其他的p還有任務(wù),此時如果global
runqueue沒有任務(wù)g了,那么p不得不從其他的p里拿一些g來執(zhí)行。一般來說,如果p從其他的p那里要拿任務(wù)的話,一般就拿run
queue的一半,這就確保了每個os線程都能充分的使用,如下圖:
三、gpm創(chuàng)建相關(guān)問題m和p的數(shù)量如何確定?或者說何時會創(chuàng)建m和p?
1、p的數(shù)量:
由啟動時環(huán)境變量$gomaxprocs或者是由runtime的方法gomaxprocs()決定(默認是1)。這意味著在程序執(zhí)行的任意時刻都只有$gomaxprocs個goroutine在同時運行。
2、m的數(shù)量:
go語言本身的限制:go程序啟動時,會設(shè)置m的最大數(shù)量,默認10000.但是內(nèi)核很難支持這么多的線程數(shù),所以這個限制可以忽略。runtime/debug中的setmaxthreads函數(shù),設(shè)置m的最大數(shù)量一個m阻塞了,會創(chuàng)建新的m。
m與p的數(shù)量沒有絕對關(guān)系,一個m阻塞,p就會去創(chuàng)建或者切換另一個m,所以,即使p的默認數(shù)量是1,也有可能會創(chuàng)建很多個m出來。
3、p何時創(chuàng)建:在確定了p的最大數(shù)量n后,運行時系統(tǒng)會根據(jù)這個數(shù)量創(chuàng)建n個p。
4、m何時創(chuàng)建:沒有足夠的m來關(guān)聯(lián)p并運行其中的可運行的g。比如所有的m此時都阻塞住了,而p中還有很多就緒任務(wù),就會去尋找空閑的m,而沒有空閑的,就會去創(chuàng)建新的m。
m選擇哪一個p關(guān)聯(lián)?m會選擇導(dǎo)致此m被創(chuàng)建的那個p關(guān)聯(lián)。什么時候會切換p與m的關(guān)聯(lián)關(guān)系?
當m因系統(tǒng)調(diào)用而阻塞時(m上運行的g進入了系統(tǒng)調(diào)用的時候),m與p會分開,如果此時p的就緒隊列中還有任務(wù),
p就會去關(guān)聯(lián)一個空閑的m,或者創(chuàng)建一個m進行關(guān)聯(lián)。(也就是說go不是像libtask一樣處理io阻塞的?不確定。)
就緒的g如何選擇進入哪個p的就緒隊列?默認情況下:因為p的默認數(shù)量是1(m不一定是1),所以如果我們不改變gomaxprocs,無論我們在程序中用go語句創(chuàng)建多少個goroutine,它們都只會被塞入同一個p的就緒隊列中。有多個p的情況下:如果修改了gomaxprocs或者調(diào)用了runtime.gomaxprocs,運行時系統(tǒng)會把所有的g均勻的分布在各個p的就緒隊列中。如何保證每個p的就緒隊列中都會有g(shù)
如果一個p的就緒隊列所有任務(wù)都執(zhí)行完了,那么p會嘗試從其他p的就緒隊列中取出一部分到自己的就緒隊列中,以保證每個p的就緒隊列都有任務(wù)可以執(zhí)行。
上一個:普洱茶的包裝為什么沒有日期?
下一個:WINDOWS是什么意思,WINDOWS什么意思

華為手機和蘋果手機哪個分辨率高(華為的屏幕分辨率永遠比不上蘋果)
德國labom壓力傳感器
手機怎么設(shè)置網(wǎng)頁黑名單,手機怎么拉黑一個網(wǎng)址
蘋果電腦怎么把文件復(fù)制到優(yōu)盤(蘋果電腦怎么把文件復(fù)制到u盤里)
買了華為云服務(wù)器有多少儲存
6s電量消耗怎么一直顯示100,蘋果6S用了一整天電池還顯示用量100什么問題
榮耀7虛擬通話怎么設(shè)置,華為的虛擬高清通話有必要開啟嗎
不當?shù)美V訟時效過了怎么辦
小米5怎么強制重啟,難道小米五只能強制重啟不能強制關(guān)機手機進水了觸屏不能用 所有辦
鐵線蕨與家居風水
十八禁 网站在线观看免费视频_2020av天堂网_一 级 黄 色 片免费网站_绝顶高潮合集Videos