在Go語(yǔ)言中,GMP調(diào)度模型是實(shí)現(xiàn)并發(fā)的重要手段之一。GMP調(diào)度模型的核心思想是將M(Machine)、G(Goroutine)和P(Processor)三個(gè)概念分離開來(lái),通過調(diào)度器來(lái)協(xié)調(diào)它們之間的關(guān)系,從而實(shí)現(xiàn)高效的并發(fā)。
M(Machine)
M代表著操作系統(tǒng)中的線程,它是Go語(yǔ)言中的執(zhí)行單位。在程序啟動(dòng)時(shí),Go語(yǔ)言會(huì)創(chuàng)建一定數(shù)量的M,每個(gè)M都會(huì)綁定一個(gè)P。M的數(shù)量默認(rèn)是CPU核心數(shù),但是可以通過GOMAXPROCS環(huán)境變量來(lái)設(shè)置。
G(Goroutine)
Goroutine是Go語(yǔ)言中的輕量級(jí)線程,它可以與M一起調(diào)度執(zhí)行。在程序中,我們可以通過關(guān)鍵字go來(lái)啟動(dòng)一個(gè)Goroutine,例如:
go func() {// 處理業(yè)務(wù)邏輯}()
在上面的例子中,我們使用Go關(guān)鍵字啟動(dòng)了一個(gè)Goroutine,并在其中執(zhí)行業(yè)務(wù)邏輯。需要注意的是,Goroutine是由Go語(yǔ)言的運(yùn)行時(shí)(runtime)進(jìn)行調(diào)度的,而不是由操作系統(tǒng)進(jìn)行調(diào)度,因此它具有輕量級(jí)、高效等特點(diǎn)。
P(Processor)
Processor是Go語(yǔ)言中的處理器,它負(fù)責(zé)將Goroutine分配給M執(zhí)行。每個(gè)M都會(huì)綁定一個(gè)P,而P的數(shù)量可以通過runtime.NumCPU()來(lái)獲?。ú煌贛的數(shù)量)。
調(diào)度器
調(diào)度器是GMP調(diào)度模型的核心,它負(fù)責(zé)將Goroutine分配給M執(zhí)行,并在M的數(shù)量不足時(shí)創(chuàng)建新的M。調(diào)度器還可以將M從一個(gè)P轉(zhuǎn)移到另一個(gè)P,以達(dá)到負(fù)載均衡的目的。
調(diào)度器的實(shí)現(xiàn)方式比較復(fù)雜,但是它的工作原理可以簡(jiǎn)單概括如下:
– 當(dāng)一個(gè)Goroutine被啟動(dòng)時(shí),它會(huì)被放入一個(gè)全局的運(yùn)行隊(duì)列中(稱為全局隊(duì)列)。
– 當(dāng)一個(gè)M空閑時(shí),它會(huì)從全局隊(duì)列中獲取一個(gè)Goroutine,并開始執(zhí)行它。
– 當(dāng)一個(gè)Goroutine阻塞時(shí),它會(huì)被放入一個(gè)本地的等待隊(duì)列中(稱為本地隊(duì)列)。
– 當(dāng)一個(gè)M中的本地隊(duì)列為空時(shí),它會(huì)從全局隊(duì)列中獲取一批Goroutine,并將它們放入本地隊(duì)列中。
– 當(dāng)一個(gè)P中的本地隊(duì)列為空時(shí),它會(huì)從其他P中的本地隊(duì)列中獲取一批Goroutine,并將它們放入本地隊(duì)列中。
– 當(dāng)一個(gè)M執(zhí)行時(shí)間過長(zhǎng)時(shí),調(diào)度器會(huì)中斷它的執(zhí)行,并將它的狀態(tài)保存到一個(gè)全局的掛起隊(duì)列中。下次該M被分配到執(zhí)行時(shí),它會(huì)從掛起隊(duì)列中恢復(fù)狀態(tài),并繼續(xù)執(zhí)行。
– 當(dāng)一個(gè)M執(zhí)行的Goroutine數(shù)量達(dá)到一定閾值時(shí),調(diào)度器會(huì)將它的狀態(tài)保存到一個(gè)全局的休眠隊(duì)列中。下次該M被分配到執(zhí)行時(shí),它會(huì)從休眠隊(duì)列中恢復(fù)狀態(tài),并繼續(xù)執(zhí)行。
下面我們來(lái)看一個(gè)簡(jiǎn)單的示例,它通過啟動(dòng)多個(gè)Goroutine來(lái)計(jì)算斐波那契數(shù)列的值:
package mainimport "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)}
在上面的例子中,我們啟動(dòng)了10個(gè)Goroutine,并在其中計(jì)算斐波那契數(shù)列的值。由于斐波那契數(shù)列的計(jì)算是CPU密集型的,因此這個(gè)程序會(huì)利用GMP調(diào)度模型來(lái)實(shí)現(xiàn)高效的并發(fā)。
注意事項(xiàng)
在使用GMP調(diào)度模型時(shí),需要注意以下幾點(diǎn):
– 不要在Goroutine中阻塞或者進(jìn)行長(zhǎng)時(shí)間的計(jì)算,這會(huì)導(dǎo)致M被掛起或者休眠,從而影響程序的性能。
– 不要在Goroutine中訪問共享資源時(shí)不加鎖,這會(huì)導(dǎo)致數(shù)據(jù)競(jìng)爭(zhēng),從而引發(fā)難以排查的bug。
– 不要將過多的Goroutine放入全局隊(duì)列中,這會(huì)導(dǎo)致調(diào)度器的性能下降,從而影響程序的性能。
– 不要將過多的M創(chuàng)建出來(lái),這會(huì)導(dǎo)致系統(tǒng)資源的浪費(fèi),從而影響程序的性能。
#從今天起記錄我的2023#
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。