golang gmp工作原理

初始化

image.png

g生命周期

image.png

newproc函數(shù)

這段代碼的邏輯如下:

  1. 函數(shù)newproc接收一個指向funcval類型的指針fn作為參數(shù)娱俺。
  2. 獲取當(dāng)前的goroutine(gp)和調(diào)用者的程序計數(shù)器(pc)。
  3. 在系統(tǒng)棧上運行一個函數(shù)废麻,該函數(shù)會執(zhí)行以下操作:
    ○ 調(diào)用newproc1函數(shù)荠卷,以fn、gp和pc作為參數(shù)烛愧,創(chuàng)建一個新的goroutine(newg)油宜。
    ○ 獲取當(dāng)前的P(處理器)的指針(pp)。
    ○ 將新創(chuàng)建的goroutine(newg)放入P的運行隊列(runq)中怜姿。
    ○ 如果main函數(shù)已經(jīng)開始運行(mainStarted為真)慎冤,則喚醒P。
    總結(jié):這段代碼的目的是創(chuàng)建一個新的goroutine沧卢,并將其放入P的運行隊列中蚁堤,然后根據(jù)需要喚醒P。

_StackMin = 2048

newproc1函數(shù)

這段代碼是Go語言中用于創(chuàng)建新的goroutine的代碼但狭。下面是代碼的邏輯解釋:

  1. 首先披诗,檢查傳入的函數(shù)指針是否為nil,如果是nil立磁,則調(diào)用fatal函數(shù)報錯呈队。
  2. 調(diào)用acquirem函數(shù)獲取當(dāng)前goroutine所在的m對象,并禁用搶占唱歧,因為之后會使用m和p局部變量宪摧。
  3. 獲取當(dāng)前p對象。
  4. 調(diào)用gfget函數(shù)從p中獲取一個空閑的g對象,如果沒有空閑的g對象绍刮,則調(diào)用malg函數(shù)創(chuàng)建一個新的g對象(_StackMin)温圆。
  5. 檢查新的g對象是否已經(jīng)分配了棧空間孩革,如果沒有岁歉,則拋出錯誤。
  6. 檢查新的g對象的狀態(tài)是否為_Gdead膝蜈,如果不是锅移,則拋出錯誤。
  7. 計算需要分配給新的g對象的棻ゲ空間的大小非剃,并對齊到系統(tǒng)的棧對齊大小。
  8. 根據(jù)是否使用LR寄存器推沸,設(shè)置調(diào)用者的LR寄存器的值备绽,并準備調(diào)用goexit函數(shù)的棧幀。
  9. 使用memclrNoHeapPointers函數(shù)清零新的g對象的sched字段鬓催,并設(shè)置sched.sp和newg.stktopsp的值為棧頂?shù)刂贰?/li>
  10. 設(shè)置sched.pc為goexit函數(shù)的地址(加上PCQuantum以確保前一條指令在同一個函數(shù)中)肺素。
  11. 調(diào)用gostartcallfn函數(shù)啟動新的goroutine,并傳入sched和函數(shù)指針宇驾。
  12. 設(shè)置新的g對象的gopc字段為調(diào)用者的PC值倍靡。
  13. 保存調(diào)用者的callergp對象,并設(shè)置為新的g對象的ancestors字段课舍。
  14. 設(shè)置新的g對象的startpc字段為函數(shù)的地址塌西。
  15. 如果新的g對象是系統(tǒng)goroutine,則增加系統(tǒng)goroutine計數(shù)筝尾。
  16. 如果當(dāng)前m對象的curg字段不為nil捡需,則將其標簽賦值給新的g對象的labels字段。
  17. 如果goroutine profile處于活動狀態(tài)忿等,將新的g對象的goroutineProfiled字段設(shè)置為goroutineProfileSatisfied栖忠。
  18. 生成一個隨機數(shù),并檢查是否滿足跟蹤條件(每隔一定周期進行跟蹤)贸街,如果滿足庵寞,則將新的g對象的tracking字段設(shè)置為true。
  19. 將新的g對象的狀態(tài)由_Gdead變?yōu)開Grunnable薛匪。
  20. 將新的g對象的棧添加到GC控制器的可掃描堆棧列表中捐川。
  21. 檢查p對象的goidcache是否已滿,如果滿了逸尖,則重新分配一批goid古沥。
  22. 為新的g對象分配一個唯一的goid瘸右,并將p的goidcache遞增。
  23. 如果啟用了race檢測岩齿,調(diào)用racegostart函數(shù)為新的g對象啟動race檢測太颤,并初始化raceignore字段。
  24. 如果新的g對象的labels字段不為nil盹沈,則調(diào)用racereleasemergeg函數(shù)與信號處理程序中的讀取同步龄章。
  25. 如果啟用了trace,調(diào)用traceGoCreate函數(shù)記錄goroutine的創(chuàng)建乞封。
  26. 調(diào)用releasem函數(shù)釋放m對象做裙。
  27. 返回新的g對象。

m生命周期

image.png

schedule函數(shù)

這段代碼是Go語言運行時調(diào)度器的核心邏輯肃晚。它用于在多個M(線程)之間分配可運行的G(協(xié)程)锚贱。
代碼的主要邏輯如下:

  1. 獲取當(dāng)前G所屬的M(線程)。
  2. 如果M持有鎖定关串,則拋出異常拧廊。
  3. 如果M鎖定了G,則停止當(dāng)前M悍缠,并執(zhí)行被鎖定的G卦绣,這個過程不會返回耐量。
  4. 如果M正在執(zhí)行cgo調(diào)用飞蚓,則拋出異常。
  5. 進入循環(huán)廊蜒,直到找到可運行的G趴拧。
  6. 如果M處于旋轉(zhuǎn)狀態(tài)(spinning)但本地運行隊列不為空,則拋出異常山叮。
  7. 調(diào)用findRunnable()函數(shù)查找可運行的G著榴,該函數(shù)會阻塞直到有可運行的G。
  8. 如果M處于旋轉(zhuǎn)狀態(tài)屁倔,則重置該狀態(tài)并可能啟動新的旋轉(zhuǎn)M脑又。
  9. 如果調(diào)度器被禁用且當(dāng)前G不允許被調(diào)度,則將其放入待運行列表锐借,并繼續(xù)查找下一個可運行的G问麸。
  10. 如果需要喚醒一個P(處理器),則喚醒它钞翔。
  11. 如果當(dāng)前G鎖定了M严卖,則將當(dāng)前的P交給鎖定的M,并阻塞等待一個新的P布轿。
  12. 執(zhí)行可運行的G哮笆,繼續(xù)下一輪調(diào)度来颤。
    總體上,這段代碼的邏輯是通過循環(huán)不斷地在多個M之間分配可運行的G稠肘,并根據(jù)不同的情況進行相應(yīng)的處理福铅。

sysmon

image.png

sysmon函數(shù)

這段代碼是Go調(diào)度器的sysmon函數(shù),它是一個系統(tǒng)監(jiān)控的循環(huán)项阴。以下是代碼邏輯的解釋:

  1. 初始化變量和計數(shù)器:初始化lasttrace本讥、idle和delay等變量。
  2. 進入循環(huán):進入一個無限循環(huán)鲁冯,直到程序退出拷沸。
  3. 計算延遲時間:根據(jù)idle的值計算延遲時間delay。如果idle為0薯演,則延遲時間為20微秒撞芍。如果idle大于50,則延遲時間加倍跨扮。如果延遲時間超過10毫秒序无,則將其設(shè)置為10毫秒。
  4. 睡眠:根據(jù)延遲時間衡创,調(diào)用usleep函數(shù)進入睡眠狀態(tài)帝嗡。
  5. 檢查是否需要喚醒:根據(jù)一些條件判斷是否需要喚醒sysmon。如果滿足條件璃氢,使用notetsleep函數(shù)進行睡眠哟玷,并在喚醒時重置idle和delay的值。
  6. 鎖定sysmonlock:獲取sysmonlock的互斥鎖一也。
  7. 觸發(fā)libc攔截器:如果需要巢寡,觸發(fā)libc的攔截器。
  8. 網(wǎng)絡(luò)輪詢:如果距離上次輪詢網(wǎng)絡(luò)超過10毫秒椰苟,調(diào)用netpoll函數(shù)進行網(wǎng)絡(luò)輪詢抑月。如果返回的列表不為空,調(diào)用injectglist函數(shù)將這些goroutine添加到可運行隊列中舆蝴。
  9. 處理netbsd的定時器:如果是netbsd操作系統(tǒng)谦絮,并且存在定時器處理的bug,調(diào)用startm函數(shù)啟動一個新的M來處理定時器洁仗。
  10. 喚醒scavenger:如果有人請求喚醒scavenger层皱,調(diào)用scavenger的wake函數(shù)。
  11. 重新獲取P和搶占:調(diào)用retake函數(shù)重新獲取被阻塞在系統(tǒng)調(diào)用中的P京痢,并搶占運行時間較長的G奶甘。如果成功獲取到P,則將idle重置為0祭椰,否則idle遞增臭家。
  12. 強制GC:如果滿足觸發(fā)GC的條件疲陕,并且沒有正在進行的GC,調(diào)用forcegc函數(shù)進行強制GC钉赁。
  13. 調(diào)試輸出:如果調(diào)試級別大于0蹄殃,并且距離上次輸出的時間大于等于指定的間隔時間,調(diào)用schedtrace函數(shù)進行調(diào)度跟蹤你踩。
  14. 解鎖sysmonlock:釋放sysmonlock的互斥鎖诅岩。
    以上是sysmon函數(shù)的邏輯解釋,它主要負責(zé)監(jiān)控系統(tǒng)狀態(tài)带膜,并根據(jù)條件進行相應(yīng)的處理吩谦,例如喚醒、輪詢網(wǎng)絡(luò)膝藕、重新獲取P等式廷。

retake函數(shù)

該段代碼是一個用于調(diào)度處理器(P)的函數(shù)。它首先獲取一個鎖(allpLock)來確保在處理過程中不會發(fā)生allp片段的更改芭挽。然后滑废,它遍歷所有的P(處理器),對于每個P袜爪,它執(zhí)行以下操作:

  1. 檢查P是否為nil蠕趁,如果是,則跳過該P辛馆。
  2. 檢查P的狀態(tài)(status)俺陋。如果狀態(tài)為_Prunning或_Psyscall,表示P正在運行或正在執(zhí)行系統(tǒng)調(diào)用怀各。
  3. 如果P的調(diào)度計數(shù)(schedtick)發(fā)生變化倔韭,說明P在運行時間過長,需要搶占它瓢对。并記錄當(dāng)前時間和搶占時間。
  4. 如果P的搶占時間加上forcePreemptNS(超過一定時間)小于當(dāng)前時間胰苏,表示需要搶占G(goroutine)硕蛹。調(diào)用preemptone函數(shù)搶占G。如果狀態(tài)為_Psyscall硕并,則還需要設(shè)置sysretake為true法焰。
  5. 如果狀態(tài)為_Psyscall,表示P正在執(zhí)行系統(tǒng)調(diào)用倔毙。檢查系統(tǒng)調(diào)用計數(shù)(syscalltick)埃仪,如果發(fā)生變化,記錄當(dāng)前時間和系統(tǒng)調(diào)用時間陕赃,并跳過該P卵蛉。
  6. 檢查是否存在其他任務(wù)需要處理颁股,以及當(dāng)前是否有空閑的M(線程),并且系統(tǒng)調(diào)用時間加上一定時間(至少20微秒)大于當(dāng)前時間傻丝。如果是甘有,則跳過該P。
  7. 釋放allpLock鎖葡缰,以便獲取sched.lock鎖亏掀。
  8. 在執(zhí)行CAS(Compare-and-Swap)操作之前,需要減少空閑的M的數(shù)量(假裝有一個額外的M正在運行)泛释,以防止從我們重新獲取的M退出系統(tǒng)調(diào)用滤愕,增加nmidle并報告死鎖。
  9. 如果CAS操作成功怜校,將P的狀態(tài)更改為_Pidle该互,增加n的計數(shù),并將syscalltick遞增韭畸,并將P移交給其他M處理宇智。
  10. 增加空閑的M的數(shù)量。
  11. 重新獲取allpLock鎖胰丁。
    最后随橘,該函數(shù)返回n的值,表示成功搶占的P的數(shù)量锦庸。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末机蔗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子甘萧,更是在濱河造成了極大的恐慌萝嘁,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扬卷,死亡現(xiàn)場離奇詭異牙言,居然都是意外死亡,警方通過查閱死者的電腦和手機怪得,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門咱枉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人徒恋,你說我怎么就攤上這事蚕断。” “怎么了入挣?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵亿乳,是天一觀的道長。 經(jīng)常有香客問我径筏,道長葛假,這世上最難降的妖魔是什么障陶? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮桐款,結(jié)果婚禮上咸这,老公的妹妹穿的比我還像新娘。我一直安慰自己魔眨,他們只是感情好媳维,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遏暴,像睡著了一般侄刽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上朋凉,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天州丹,我揣著相機與錄音,去河邊找鬼杂彭。 笑死墓毒,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的亲怠。 我是一名探鬼主播所计,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼团秽!你這毒婦竟也來了主胧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤习勤,失蹤者是張志新(化名)和其女友劉穎踪栋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體图毕,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡夷都,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了吴旋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片损肛。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖荣瑟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情摩泪,我是刑警寧澤笆焰,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站见坑,受9級特大地震影響嚷掠,放射性物質(zhì)發(fā)生泄漏捏检。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一不皆、第九天 我趴在偏房一處隱蔽的房頂上張望贯城。 院中可真熱鬧,春花似錦霹娄、人聲如沸能犯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踩晶。三九已至,卻和暖如春枕磁,著一層夾襖步出監(jiān)牢的瞬間渡蜻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工计济, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茸苇,地道東北人。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓沦寂,卻偏偏與公主長得像学密,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子凑队,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容