Go并發(fā)編程-線(xiàn)程模型(P)

P(執(zhí)行一個(gè)Go代碼片段所必需的資源)
P是G能夠在M中運(yùn)行的關(guān)鍵。Go的運(yùn)行時(shí)系統(tǒng)會(huì)適時(shí)地讓P與不同的M建立或斷開(kāi)關(guān)聯(lián),以使P中的那些可運(yùn)行的G能夠及時(shí)獲得運(yùn)行時(shí)機(jī),這與操作系統(tǒng)內(nèi)核在CPU之上實(shí)時(shí)地切換不同的進(jìn)程或線(xiàn)程的情形類(lèi)似。

改變單個(gè)Go程序間接擁有的P的最大數(shù)量有兩種方法。

  • 第一種方法,調(diào)用函數(shù)runtime.GOMAXPROCS并把想要設(shè)定的數(shù)量作為參數(shù)傳入。
  • 第二種方法,在Go程序運(yùn)行前設(shè)置環(huán)境變量GOMAXPROCS的值。

P的最大數(shù)量實(shí)際上是對(duì)程序中并發(fā)運(yùn)行的G的規(guī)模的一種限制。P的數(shù)量即為可運(yùn)行G的隊(duì)列的數(shù)量。一個(gè)G在被啟用后,會(huì)先被追加到某個(gè)P的可運(yùn)行G隊(duì)列中,以等待運(yùn)行時(shí)機(jī)。一個(gè)P只有與一個(gè)M關(guān)聯(lián)在一起時(shí),才會(huì)使其可運(yùn)行G隊(duì)列中的G有機(jī)會(huì)運(yùn)行。
不過(guò),設(shè)置P的最大數(shù)量只能限制住P的數(shù)量,而對(duì)G和M的數(shù)量沒(méi)有任何約束。當(dāng)M因系統(tǒng)調(diào)用而阻塞(更確切地說(shuō),是它運(yùn)行的G進(jìn)入了系統(tǒng)調(diào)用)的時(shí)候,運(yùn)行時(shí)系統(tǒng)會(huì)把該M和與之關(guān)聯(lián)的P分離開(kāi)來(lái)。這時(shí),如果這個(gè)P的可運(yùn)行G隊(duì)列中還有未被運(yùn)行的G,那么運(yùn)行時(shí)系統(tǒng)就會(huì)找到一個(gè)空閑M,或創(chuàng)建一個(gè)新的M,并與該P(yáng)關(guān)聯(lián)以滿(mǎn)足這些G的運(yùn)行需要。因此,M的數(shù)量在很多時(shí)候也都會(huì)比P多。而G的數(shù)量,一般取決于Go程序本身。

確定P的最大數(shù)量之后,運(yùn)行時(shí)系統(tǒng)會(huì)根據(jù)這個(gè)數(shù)值重整全局的P列表(runtime. allp)。與全局M列表類(lèi)似,該列表中包含了當(dāng)前運(yùn)行時(shí)系統(tǒng)創(chuàng)建的所有P。運(yùn)行時(shí)系統(tǒng)會(huì)把這些P中的可運(yùn)行G全部取出,并放入調(diào)度器的可運(yùn)行G隊(duì)列中。這是調(diào)整全局P列表的一個(gè)重要前提。被轉(zhuǎn)移的那些G,會(huì)在以后經(jīng)由調(diào)度再次放入某個(gè)P的可運(yùn)行G隊(duì)列。

與空閑M列表類(lèi)似,運(yùn)行時(shí)系統(tǒng)中也存在一個(gè)調(diào)度器的空閑P列表(runtime.sched.pidle)。當(dāng)一個(gè)P不再與任何M關(guān)聯(lián)的時(shí)候,運(yùn)行時(shí)系統(tǒng)就會(huì)把它放入該列表;而當(dāng)運(yùn)行時(shí)系統(tǒng)需要一個(gè)空閑的P關(guān)聯(lián)某個(gè)M的話(huà),會(huì)從此列表中取出一個(gè)。
注意,P進(jìn)入空閑P列表的一個(gè)前提條件是它的可運(yùn)行G列表必須為空。例如,在重整全局P列表的時(shí)候,P在被清空可運(yùn)行G隊(duì)列之后,才會(huì)被放入空閑P列表。

與M不同,P本身是有狀態(tài)的,可能具有的狀態(tài)如下。

  • Pidle: 此狀態(tài)表明當(dāng)前P未與任何M存在關(guān)聯(lián)。
  • Prunning: 此狀態(tài)表明當(dāng)前P正在與某個(gè)M關(guān)聯(lián)。
  • Psyscall: 此狀態(tài)表明當(dāng)前P中的運(yùn)行的那個(gè)G正在進(jìn)行系統(tǒng)調(diào)用。
  • Pgcstop: 此狀態(tài)表明運(yùn)行時(shí)系統(tǒng)需要停止調(diào)度。例如,運(yùn)行時(shí)系統(tǒng)在開(kāi)始垃圾回收的某些步驟前,就會(huì)試圖把全局P列表中的所有P都置于此狀態(tài)。
  • Pdead: 此狀態(tài)表明當(dāng)前P已經(jīng)不會(huì)再被使用。如果在Go程序運(yùn)行的過(guò)程中,通過(guò)調(diào)用runtime.GOMAXPROCS函數(shù)減少了P的最大數(shù)量,那么多余的P就會(huì)被運(yùn)行時(shí)系統(tǒng)置于此狀態(tài)。

P在創(chuàng)建之初的狀態(tài)是Pgcstop,雖然這并不意味著運(yùn)行時(shí)系統(tǒng)要在這時(shí)進(jìn)行垃圾回收。不過(guò),P處于這一初始狀態(tài)的時(shí)間會(huì)非常短暫。在緊接著的初始化之后,運(yùn)行時(shí)系統(tǒng)會(huì)將其狀態(tài)設(shè)置為Pidle,并放入調(diào)度器的空閑P列表。下圖描繪了P在各個(gè)狀態(tài)之間進(jìn)行流轉(zhuǎn)的具體情況。


P的狀態(tài)轉(zhuǎn)換

可以看到,非Pdead狀態(tài)的P都會(huì)在運(yùn)行時(shí)系統(tǒng)欲停止調(diào)度時(shí)被置于Pgcstop狀態(tài)。不過(guò),等到需要重啟調(diào)度的時(shí)候(如垃圾回收結(jié)束后),它們并不會(huì)被恢復(fù)至原有狀態(tài),而會(huì)被統(tǒng)一地轉(zhuǎn)換為Pidle狀態(tài)。也就是說(shuō),它們會(huì)被放到同一起跑線(xiàn)上,并公平地接受再次調(diào)度。另一方面,非Pgcstop狀態(tài)的P都可能因全局P列表的縮小而被認(rèn)為是多余的,并被置于Pdead狀態(tài)。
不過(guò),我們并不用擔(dān)心其中的G會(huì)失去歸宿。因?yàn)椋赑被轉(zhuǎn)換為Pdead狀態(tài)之前,其可運(yùn)行G隊(duì)列中的G都會(huì)被轉(zhuǎn)移到調(diào)度器的可運(yùn)行G隊(duì)列,而它的自由G列表中的G也都會(huì)被轉(zhuǎn)移到調(diào)度器的自由G列表中。

正如前面所述,每個(gè)P中除了一個(gè)可運(yùn)行G隊(duì)列外,還都包含一個(gè)自由G列表。這個(gè)列表中包含了一些已經(jīng)運(yùn)行完成的G。隨著運(yùn)行完成的G的增多,該列表可能會(huì)很長(zhǎng)。如果它增長(zhǎng)到一定程度,運(yùn)行時(shí)系統(tǒng)就會(huì)把其中的部分G轉(zhuǎn)移到調(diào)度器的自由G列表中。
另一方面,當(dāng)使用go語(yǔ)句啟用一個(gè)G的時(shí)候,運(yùn)行時(shí)系統(tǒng)會(huì)先試圖從相應(yīng)P的自由G列表中獲取一個(gè)現(xiàn)成的G,來(lái)封裝這個(gè)go語(yǔ)句攜帶的函數(shù)(也稱(chēng)go函數(shù)),僅當(dāng)獲取不到這樣一個(gè)G的時(shí)候才有可能創(chuàng)建一個(gè)新的G??紤]到相應(yīng)P的自由G列表為空而獲取不到自由G的情況,運(yùn)行時(shí)系統(tǒng)會(huì)在發(fā)現(xiàn)其中的自由G太少時(shí),預(yù)先嘗試從調(diào)度器的自由G列表中轉(zhuǎn)移過(guò)來(lái)一些G。如此一來(lái),只有在調(diào)度器的自由G列表也彈盡糧絕的時(shí)候,才會(huì)有新的G被創(chuàng)建。這在很大程度上提高了G的復(fù)用率。

在P的結(jié)構(gòu)中,可運(yùn)行G隊(duì)列和自由G列表是最重要的兩個(gè)成員。至少對(duì)于Go語(yǔ)言的使用者來(lái)說(shuō)是這樣。它們間接地體現(xiàn)了運(yùn)行時(shí)系統(tǒng)對(duì)G的調(diào)度情況。

相關(guān)鏈接:
Go并發(fā)編程-線(xiàn)程模型
Go并發(fā)編程-線(xiàn)程模型(M)
Go并發(fā)編程-線(xiàn)程模型(P)
Go并發(fā)編程-線(xiàn)程模型(G)

參考資料:
https://www.ituring.com.cn/book/tupubarticle/16048

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容