在Go語言中砖茸,GMP調(diào)度模型是實現(xiàn)并發(fā)的重要手段之一堰怨。GMP調(diào)度模型的核心思想是將M(Machine)二鳄、G(Goroutine)和P(Processor)三個概念分離開來奥溺,通過調(diào)度器來協(xié)調(diào)它們之間的關系好港,從而實現(xiàn)高效的并發(fā)愉镰。
M(Machine)
M代表著操作系統(tǒng)中的線程,它是Go語言中的執(zhí)行單位钧汹。在程序啟動時丈探,Go語言會創(chuàng)建一定數(shù)量的M,每個M都會綁定一個P拔莱。M的數(shù)量默認是CPU核心數(shù)碗降,但是可以通過GOMAXPROCS環(huán)境變量來設置。
G(Goroutine)
Goroutine是Go語言中的輕量級線程塘秦,它可以與M一起調(diào)度執(zhí)行讼渊。在程序中,我們可以通過關鍵字go來啟動一個Goroutine尊剔,例如:
go func() {
// 處理業(yè)務邏輯
}()
在上面的例子中爪幻,我們使用go關鍵字啟動了一個Goroutine,并在其中執(zhí)行業(yè)務邏輯须误。需要注意的是挨稿,Goroutine是由Go語言的運行時(runtime)進行調(diào)度的,而不是由操作系統(tǒng)進行調(diào)度京痢,因此它具有輕量級奶甘、高效等特點。
P(Processor)
Processor是Go語言中的處理器祭椰,它負責將Goroutine分配給M執(zhí)行臭家。每個M都會綁定一個P,而P的數(shù)量可以通過runtime.NumCPU()來獲确接佟(不同于M的數(shù)量)侣监。
調(diào)度器
調(diào)度器是GMP調(diào)度模型的核心,它負責將Goroutine分配給M執(zhí)行臣淤,并在M的數(shù)量不足時創(chuàng)建新的M橄霉。調(diào)度器還可以將M從一個P轉(zhuǎn)移到另一個P,以達到負載均衡的目的。
調(diào)度器的實現(xiàn)方式比較復雜姓蜂,但是它的工作原理可以簡單概括如下:
- 當一個Goroutine被啟動時按厘,它會被放入一個全局的運行隊列中(稱為全局隊列)。
- 當一個M空閑時钱慢,它會從全局隊列中獲取一個Goroutine逮京,并開始執(zhí)行它。
- 當一個Goroutine阻塞時束莫,它會被放入一個本地的等待隊列中(稱為本地隊列)懒棉。
- 當一個M中的本地隊列為空時,它會從全局隊列中獲取一批Goroutine览绿,并將它們放入本地隊列中策严。
- 當一個P中的本地隊列為空時,它會從其他P中的本地隊列中獲取一批Goroutine饿敲,并將它們放入本地隊列中妻导。
- 當一個M執(zhí)行時間過長時,調(diào)度器會中斷它的執(zhí)行怀各,并將它的狀態(tài)保存到一個全局的掛起隊列中倔韭。下次該M被分配到執(zhí)行時,它會從掛起隊列中恢復狀態(tài)瓢对,并繼續(xù)執(zhí)行寿酌。
- 當一個M執(zhí)行的Goroutine數(shù)量達到一定閾值時,調(diào)度器會將它的狀態(tài)保存到一個全局的休眠隊列中硕蛹。下次該M被分配到執(zhí)行時醇疼,它會從休眠隊列中恢復狀態(tài),并繼續(xù)執(zhí)行妓美。
下面我們來看一個簡單的示例,它通過啟動多個Goroutine來計算斐波那契數(shù)列的值:
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
go func() {
fmt.Println(fib(40))
}()
}
}
func fib(n int) int {
if n < 2 {
return n
}
return fib(n-1) + fib(n-2)
}
在上面的例子中鲤孵,我們啟動了10個Goroutine壶栋,并在其中計算斐波那契數(shù)列的值。由于斐波那契數(shù)列的計算是CPU密集型的普监,因此這個程序會利用GMP調(diào)度模型來實現(xiàn)高效的并發(fā)贵试。
注意事項
在使用GMP調(diào)度模型時,需要注意以下幾點:
- 不要在Goroutine中阻塞或者進行長時間的計算凯正,這會導致M被掛起或者休眠毙玻,從而影響程序的性能。
- 不要在Goroutine中訪問共享資源時不加鎖廊散,這會導致數(shù)據(jù)競爭桑滩,從而引發(fā)難以排查的bug。
- 不要將過多的Goroutine放入全局隊列中允睹,這會導致調(diào)度器的性能下降运准,從而影響程序的性能幌氮。
- 不要將過多的M創(chuàng)建出來,這會導致系統(tǒng)資源的浪費胁澳,從而影響程序的性能该互。