內(nèi)核線程(Kernel-Level Thread ,KLT)
為達茂旗等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務,及達茂旗網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務為網(wǎng)站設(shè)計、成都做網(wǎng)站、達茂旗網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!
輕量級進程(Light Weight Process,LWP):輕量級進程就是我們通常意義上所講的線程,由于每個輕量級進程都由一個內(nèi)核線程支持,因此只有先支持內(nèi)核線程,才能有輕量級進程
用戶線程與系統(tǒng)線程一一對應,用戶線程執(zhí)行如lo操作的系統(tǒng)調(diào)用時,來回切換操作開銷相對比較大
多個用戶線程對應一個內(nèi)核線程,當內(nèi)核線程對應的一個用戶線程被阻塞掛起時候,其他用戶線程也阻塞不能執(zhí)行了。
多對多模型是可以充分利用多核CPU提升運行效能的
go線程模型包含三個概念:內(nèi)核線程(M),goroutine(G),G的上下文環(huán)境(P);
GMP模型是goalng特有的。
P與M一般是一一對應的。P(上下文)管理著一組G(goroutine)掛載在M(內(nèi)核線程)上運行,圖中左邊藍色為正在執(zhí)行狀態(tài)的goroutine,右邊為待執(zhí)行狀態(tài)的goroutiine隊列。P的數(shù)量由環(huán)境變量GOMAXPROCS的值或程序運行runtime.GOMAXPROCS()進行設(shè)置。
當一個os線程在執(zhí)行M1一個G1發(fā)生阻塞時,調(diào)度器讓M1拋棄P,等待G1返回,然后另起一個M2接收P來執(zhí)行剩下的goroutine隊列(G2、G3...),這是golang調(diào)度器厲害的地方,可以保證有足夠的線程來運行剩下所有的goroutine。
當G1結(jié)束后,M1會重新拿回P來完成,如果拿不到就丟到全局runqueue中,然后自己放到線程池或轉(zhuǎn)入休眠狀態(tài)??臻e的上下文P會周期性的檢查全局runqueue上的goroutine,并且執(zhí)行它。
另一種情況就是當有些P1太閑而其他P2很忙碌的時候,會從其他上下文P2拿一些G來執(zhí)行。
詳細可以翻看下方第一個參考鏈接,寫得真好。
最后用大佬的總結(jié)來做最后的收尾————
Go語言運行時,通過核心元素G,M,P 和 自己的調(diào)度器,實現(xiàn)了自己的并發(fā)線程模型。調(diào)度器通過對G,M,P的調(diào)度實現(xiàn)了兩級線程模型中操作系統(tǒng)內(nèi)核之外的調(diào)度任務。整個調(diào)度過程中會在多種時機去觸發(fā)最核心的步驟 “一整輪調(diào)度”,而一整輪調(diào)度中最關(guān)鍵的部分在“全力查找可運行G”,它保證了M的高效運行(換句話說就是充分使用了計算機的物理資源),一整輪調(diào)度中還會涉及到M的啟用停止。最后別忘了,還有一個與Go程序生命周期相同的系統(tǒng)監(jiān)測任務來進行一些輔助性的工作。
淺析Golang的線程模型與調(diào)度器
Golang CSP并發(fā)模型
Golang線程模型
無緩沖的通道(unbuffered channel)是指在接收前沒有能力保存任何值的通道。
這種類型的通道要求發(fā)送goroutine和接收goroutine同時準備好,才能完成發(fā)送和接收操作。否則,通道會導致先執(zhí)行發(fā)送或接收操作的 goroutine 阻塞等待。
這種對通道進行發(fā)送和接收的交互行為本身就是同步的。其中任意一個操作都無法離開另一個操作單獨存在。
阻塞:由于某種原因數(shù)據(jù)沒有到達,當前協(xié)程(線程)持續(xù)處于等待狀態(tài),直到條件滿足,才接觸阻塞。
同步:在兩個或多個協(xié)程(線程)間,保持數(shù)據(jù)內(nèi)容一致性的機制。
下圖展示兩個 goroutine 如何利用無緩沖的通道來共享一個值:
在第 1 步,兩個 goroutine 都到達通道,但哪個都沒有開始執(zhí)行發(fā)送或者接收。
在第 2 步,左側(cè)的 goroutine 將它的手伸進了通道,這模擬了向通道發(fā)送數(shù)據(jù)的行為。這時,這個 goroutine 會在通道中被鎖住,直到交換完成。
在第 3 步,右側(cè)的 goroutine 將它的手放入通道,這模擬了從通道里接收數(shù)據(jù)。這個 goroutine 一樣也會在通道中被鎖住,直到交換完成。
在第 4 步和第 5 步,進行交換,并最終,在第 6 步,兩個 goroutine 都將它們的手從通道里拿出來,這模擬了被鎖住的 goroutine 得到釋放。兩個 goroutine 現(xiàn)在都可以去做別的事情了。
如果沒有指定緩沖區(qū)容量,那么該通道就是同步的,因此會阻塞到發(fā)送者準備好發(fā)送和接收者準備好接收。
無緩沖channel: —— 同步通信
參考:
Goroutine并發(fā)調(diào)度模型深度解析手擼一個協(xié)程池
Golang 的 goroutine 是如何實現(xiàn)的?
Golang - 調(diào)度剖析【第二部分】
OS線程初始棧為2MB。Go語言中,每個goroutine采用動態(tài)擴容方式,初始2KB,按需增長,最大1G。此外GC會收縮??臻g。
BTW,增長擴容都是有代價的,需要copy數(shù)據(jù)到新的stack,所以初始2KB可能有些性能問題。
更多關(guān)于stack的內(nèi)容,可以參見大佬的文章。 聊一聊goroutine stack
用戶線程的調(diào)度以及生命周期管理都是用戶層面,Go語言自己實現(xiàn)的,不借助OS系統(tǒng)調(diào)用,減少系統(tǒng)資源消耗。
Go語言采用兩級線程模型,即用戶線程與內(nèi)核線程KSE(kernel scheduling entity)是M:N的。最終goroutine還是會交給OS線程執(zhí)行,但是需要一個中介,提供上下文。這就是G-M-P模型
Go調(diào)度器有兩個不同的運行隊列:
go1.10\src\runtime\runtime2.go
Go調(diào)度器根據(jù)事件進行上下文切換。
調(diào)度的目的就是防止M堵塞,空閑,系統(tǒng)進程切換。
詳見 Golang - 調(diào)度剖析【第二部分】
Linux可以通過epoll實現(xiàn)網(wǎng)絡調(diào)用,統(tǒng)稱網(wǎng)絡輪詢器N(Net Poller)。
文件IO操作
上面都是防止M堵塞,任務竊取是防止M空閑
每個M都有一個特殊的G,g0。用于執(zhí)行調(diào)度,gc,棧管理等任務,所以g0的棧稱為調(diào)度棧。g0的棧不會自動增長,不會被gc,來自os線程的棧。
go1.10\src\runtime\proc.go
G沒辦法自己運行,必須通過M運行
M通過通過調(diào)度,執(zhí)行G
從M掛載P的runq中找到G,執(zhí)行G
Go語言是一種開源的編程語言,被廣泛應用于網(wǎng)絡編程、云計算、分布式系統(tǒng)等領(lǐng)域。
go語言的三位作者
Go語言的設(shè)計目標是成為一種語法簡潔、執(zhí)行效率高、并發(fā)性能強大的編程語言。它由Google公司研發(fā),于2009年首次發(fā)布,并于2012年成為了開源項目。Go語言具有C語言的表達能力和Python的開發(fā)效率,同時還擁有自己獨特的語法和特性,如協(xié)程、垃圾回收機制等。因此,它被廣泛應用于網(wǎng)絡編程、云計算、分布式系統(tǒng)等領(lǐng)域,并且越來越受到開發(fā)者的青睞。
Go語言的出現(xiàn),填補了許多編程語言在并發(fā)編程方面的空缺。它提供了一種輕量級線程模型,通過協(xié)程(goroutine)的方式,實現(xiàn)了高效的并發(fā)編程。同時,Go語言還支持內(nèi)置的網(wǎng)絡編程和字節(jié)序列編解碼庫,使得網(wǎng)絡編程變得更加容易和高效。在云計算、分布式系統(tǒng)等領(lǐng)域,Go語言也得到了廣泛的應用。例如,Docker和Kubernetes等開源項目就是用Go語言開發(fā)的。此外,Go語言還具有代碼可讀性高、編譯速度快、編譯后的可執(zhí)行文件體積小等優(yōu)點,使得它成為了開發(fā)高性能、高并發(fā)應用的理想語言之一。