日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

如何更直观地理解 Go 调度过程

發(fā)布時(shí)間:2024/1/8 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何更直观地理解 Go 调度过程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

得益于 Go 語(yǔ)言優(yōu)秀的運(yùn)行時(shí)調(diào)度系統(tǒng),即使開(kāi)發(fā)人員沒(méi)有多線程編程經(jīng)驗(yàn),也能很容易地開(kāi)發(fā)并發(fā)程序。

調(diào)度系統(tǒng),其中最核心的就是 GMP 的設(shè)計(jì),欲深入理解 Go 語(yǔ)言設(shè)計(jì)的讀者都應(yīng)該看過(guò)這些知識(shí)。但是,在通過(guò)相關(guān)博客或者源碼學(xué)習(xí)時(shí),如果不能和實(shí)際的代碼進(jìn)行結(jié)合,在理解上或許不夠深刻。

本文介紹一種方式,即使用 GODEBUG 工具,通過(guò)實(shí)際運(yùn)行代碼來(lái)直觀地查看 Go 運(yùn)行時(shí)的調(diào)度過(guò)程。

調(diào)度簡(jiǎn)述

首先,我們先通過(guò)程序某時(shí)刻的調(diào)度快照示意圖,通過(guò)解析快照狀態(tài)來(lái)簡(jiǎn)單回顧一下 Go 調(diào)度系統(tǒng)。

如上圖所示,我們?cè)O(shè)定了 GOMAXPROCS=2,即 2 個(gè)處理器。

當(dāng)前時(shí)刻, P0 和 P1 上正分別掛載著 OS 線程 M1 與 M4,其上分別執(zhí)行著 G8 和 G17 的代碼。P0 的 LRQ(Local Run Queue,本地運(yùn)行隊(duì)列)有 3 個(gè) G 在排隊(duì)等待,而 P1 的 LRQ 已無(wú)等待的 G;GRQ (Global Run Queue,全局運(yùn)行隊(duì)列)中有 5 個(gè) G 。

網(wǎng)絡(luò)輪詢器 Net Poller 上有一個(gè)陷入異步網(wǎng)絡(luò)調(diào)用的 G9;M2 由于 G11 的某種同步系統(tǒng)調(diào)用而阻塞;M3 處于空閑狀態(tài),時(shí)刻準(zhǔn)備著當(dāng) M1 或 M4 被阻塞時(shí)而派上用場(chǎng)。

由于 P1 的 LRQ 已無(wú)等待的 G,當(dāng) G17 被調(diào)度時(shí),它將進(jìn)行 Wrok Stealing (任務(wù)竊取),其竊取源來(lái)自于其他處理器 P 的 LRQ(這里是 P1 的 LRQ)、GRQ 和 Net Poller,具體規(guī)則見(jiàn)runtime.schedule()函數(shù)。

GODEBUG 工具

啟用 GODEBUG 工具非常簡(jiǎn)單,只需要設(shè)置環(huán)境變量 GODEBUG 即可。它可以讓 Go 程序在運(yùn)行過(guò)程中輸出調(diào)試信息,能夠根據(jù)參數(shù)配置直觀地看到調(diào)度器或垃圾回收等詳細(xì)信息。

GODEBUG 的詳細(xì)描述介紹可見(jiàn)源碼runtime/extern.go文件。

本文我們關(guān)心的調(diào)試內(nèi)容是調(diào)度器,因此我們只使用 GODEBUG 的兩個(gè)參數(shù) schedtrace 與 scheddetail。

  • schedtrace=n:設(shè)置運(yùn)行時(shí)在每 n 毫秒輸出一行調(diào)度器的概要信息。

  • scheddetail: 輸出更詳細(xì)的調(diào)度信息。

示例代碼

我們使用的示例代碼如下

package?mainimport?("sync" )var?wg?sync.WaitGroupfunc?main()?{for?i?:=?0;?i?<?20;?i++?{wg.Add(1)go?work(&wg)}wg.Wait() }func?work(wg?*sync.WaitGroup)?{var?counter?intfor?i?:=?0;?i?<?1e10;?i++?{counter++}wg.Done() }

代碼比較簡(jiǎn)單,我們啟動(dòng) 20 個(gè) CPU 密集型的 G 任務(wù),它們受到 WaitGroup 的限制。當(dāng)所有計(jì)算任務(wù)的 G 完成了各自的累加工作,程序才會(huì)結(jié)束執(zhí)行。

schedtrace 調(diào)度概要輸出

下面,我們?cè)O(shè)定 GODEBUG=schedtrace=1000,這意味著 1s 輸出一次程序的調(diào)度概要情況。

$?go?build?-o?demo?main.go$?GOMAXPROCS=4?GODEBUG=schedtrace=1000?./demo SCHED?0ms:?gomaxprocs=4?idleprocs=3?threads=2?spinningthreads=0?idlethreads=0?runqueue=0?[0?0?0?0] SCHED?1003ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=14?[1?0?1?0] SCHED?2012ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=10?[2?1?2?1] SCHED?3018ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=12?[0?0?0?4] SCHED?4029ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=15?[0?0?1?0] SCHED?5031ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=9?[1?2?2?2] SCHED?6035ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=15?[0?1?0?0] SCHED?7044ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=8?[1?2?3?2] SCHED?8054ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=12?[0?0?4?0] SCHED?9055ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=6?[3?2?3?2] SCHED?10063ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=11?[1?2?1?1] SCHED?11072ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=6?[3?2?3?2] ...

其中,

  • SCHED:代表程序啟動(dòng)到輸出當(dāng)前行時(shí)的運(yùn)行時(shí)間,這個(gè)輸出間隔受到 schedtrace 值影響。

  • gomaxprocs:GOMAXPROCS 值,這里我們?cè)O(shè)定了其為 4。

  • idleprocs:空閑的 P 數(shù)量。

  • threads:運(yùn)行時(shí)管理的線程數(shù)。

  • spinningthreads:自旋線程,處于”自旋“狀態(tài)的線程數(shù)(避免頻繁的線程創(chuàng)建與銷(xiāo)毀)。

  • idlethreads:空閑線程數(shù)。

  • runqueue:全局隊(duì)列 GRQ 中的 G 數(shù)量。

  • [2 1 2 1]:代表 4 個(gè) P 的本地隊(duì)列 LRQ 中 G 數(shù)量分別是 2、1、2、1 。

scheddetail 調(diào)度詳細(xì)輸出

當(dāng)我們想要查看更詳細(xì)的調(diào)度信息時(shí),需要增加 scheddetail 參數(shù)。

$?GOMAXPROCS=4?GODEBUG=schedtrace=1000,scheddetail=1?./demo SCHED?0ms:?gomaxprocs=4?idleprocs=2?threads=3?spinningthreads=1?idlethreads=0?runqueue=0?gcwaiting=0?nmidlelocked=0?stopwait=0?sysmonwait=0P0:?status=1?schedtick=0?syscalltick=0?m=0?runqsize=0?gfreecnt=0?timerslen=0P1:?status=1?schedtick=0?syscalltick=0?m=2?runqsize=0?gfreecnt=0?timerslen=0P2:?status=0?schedtick=0?syscalltick=0?m=-1?runqsize=0?gfreecnt=0?timerslen=0P3:?status=0?schedtick=0?syscalltick=0?m=-1?runqsize=0?gfreecnt=0?timerslen=0M2:?p=1?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=2?dying=0?spinning=false?blocked=false?lockedg=-1M1:?p=-1?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=2?dying=0?spinning=false?blocked=false?lockedg=-1M0:?p=0?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=1?dying=0?spinning=false?blocked=false?lockedg=1G1:?status=1()?m=-1?lockedm=0G2:?status=1()?m=-1?lockedm=-1G3:?status=1()?m=-1?lockedm=-1 SCHED?1000ms:?gomaxprocs=4?idleprocs=0?threads=5?spinningthreads=0?idlethreads=0?runqueue=15?gcwaiting=0?nmidlelocked=0?stopwait=0?sysmonwait=0P0:?status=1?schedtick=45?syscalltick=0?m=2?runqsize=0?gfreecnt=0?timerslen=0P1:?status=1?schedtick=46?syscalltick=0?m=3?runqsize=0?gfreecnt=0?timerslen=0P2:?status=1?schedtick=45?syscalltick=0?m=4?runqsize=1?gfreecnt=0?timerslen=0P3:?status=1?schedtick=45?syscalltick=0?m=0?runqsize=0?gfreecnt=0?timerslen=0M4:?p=2?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=1?dying=0?spinning=false?blocked=false?lockedg=-1M3:?p=1?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=1?dying=0?spinning=false?blocked=false?lockedg=-1M2:?p=0?curg=40?mallocing=0?throwing=0?preemptoff=?locks=0?dying=0?spinning=false?blocked=false?lockedg=-1M1:?p=-1?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=2?dying=0?spinning=false?blocked=false?lockedg=-1M0:?p=3?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=1?dying=0?spinning=false?blocked=false?lockedg=-1G1:?status=4(semacquire)?m=-1?lockedm=-1G2:?status=4(force?gc?(idle))?m=-1?lockedm=-1G3:?status=4(GC?sweep?wait)?m=-1?lockedm=-1G17:?status=4(GC?scavenge?wait)?m=-1?lockedm=-1G33:?status=1()?m=-1?lockedm=-1G34:?status=1()?m=-1?lockedm=-1G35:?status=1()?m=-1?lockedm=-1G36:?status=1()?m=-1?lockedm=-1G37:?status=1()?m=-1?lockedm=-1G38:?status=1()?m=-1?lockedm=-1G39:?status=1()?m=-1?lockedm=-1G40:?status=2()?m=2?lockedm=-1G41:?status=1()?m=-1?lockedm=-1G42:?status=1()?m=-1?lockedm=-1G43:?status=1()?m=-1?lockedm=-1G44:?status=1()?m=-1?lockedm=-1G45:?status=1()?m=-1?lockedm=-1G46:?status=1()?m=-1?lockedm=-1G47:?status=1()?m=-1?lockedm=-1G48:?status=1()?m=-1?lockedm=-1G49:?status=1()?m=-1?lockedm=-1G50:?status=1()?m=-1?lockedm=-1G51:?status=1()?m=-1?lockedm=-1G52:?status=1()?m=-1?lockedm=-1 ...

當(dāng)增加了 scheddetail 參數(shù)后,其輸出信息不僅包含了 SCHED 的一行概覽信息,還增加了 GPM 三個(gè)實(shí)體狀況的詳細(xì)描述。

P
  • status:P 的運(yùn)行狀態(tài),其詳細(xì)分類(lèi)與描述可查看源碼 runtime/runtime2.go 的代碼。

  • schedtick:隨著每次調(diào)度行為累加,代表 P 的調(diào)度次數(shù)。

  • syscalltick:隨著每次系統(tǒng)調(diào)用行為累加,代表 P 的系統(tǒng)調(diào)用次數(shù)。

  • m: 綁定的 M 編號(hào),例如在 SCHED 1000ms 時(shí),P0 的 m=2,而 M2 的 p=0。

  • runqsize:LRQ 的 G 數(shù)量。

  • gfreecnt:狀態(tài)為 Gdead 的數(shù)量,即 status = 6。

  • timerslen:timer 的數(shù)量。

M
  • p:綁定的 P 編號(hào)。

  • curg:當(dāng)前正在 M 上執(zhí)行代碼的 G 編號(hào)。

  • mallocing:是否正存在分配內(nèi)存操作。

  • throwing:是否有拋出異常。

  • preemptoff:如果 preemptoff != "",則保持 curg 在這個(gè) M 上運(yùn)行。

  • locks:M 的 locks 數(shù)量。

  • dying:M 的 dying 值,其存在 0、1、2 和其他值四種處理情況。

  • spinning:是否處于自選狀態(tài)。

  • blocked:是否處于阻塞狀態(tài)。

  • lockedg:與 G 的 lockedm 相對(duì)應(yīng),它們的類(lèi)型是 uintptr,記錄不被垃圾收集器跟蹤的 M 與繞過(guò)寫(xiě)屏障的 G。

G
  • status: 同 P 的狀態(tài)類(lèi)似,其詳細(xì)分類(lèi)與描述同樣可查看源碼 runtime/runtime2.go 的代碼;if status==Gwaiting ,即 status 的值為 4 時(shí),其括號(hào)內(nèi)還會(huì)輸出具體的等待原因。

  • m:綁定的 M 編號(hào),如果其值為 -1,代表無(wú)綁定。

  • lockedm:與 M 中的 lockedg 對(duì)應(yīng)。

可視化調(diào)度快照

明白了上述各項(xiàng)指標(biāo)的含義之后。為了繪圖簡(jiǎn)單,我們將 GOMAXPROCS 設(shè)定為2,并選取第 1 秒的輸出內(nèi)容進(jìn)行可視化分析。

$?GOMAXPROCS=2?GODEBUG=schedtrace=1000,scheddetail=1?./demo ... SCHED?1004ms:?gomaxprocs=2?idleprocs=0?threads=4?spinningthreads=0?idlethreads=1?runqueue=10?gcwaiting=0?nmidlelocked=0?stopwait=0?sysmonwait=0P0:?status=1?schedtick=45?syscalltick=0?m=3?runqsize=4?gfreecnt=0?timerslen=0P1:?status=1?schedtick=48?syscalltick=0?m=0?runqsize=4?gfreecnt=0?timerslen=0M3:?p=0?curg=24?mallocing=0?throwing=0?preemptoff=?locks=0?dying=0?spinning=false?blocked=false?lockedg=-1M2:?p=-1?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=0?dying=0?spinning=false?blocked=true?lockedg=-1M1:?p=-1?curg=-1?mallocing=0?throwing=0?preemptoff=?locks=2?dying=0?spinning=false?blocked=false?lockedg=-1M0:?p=1?curg=34?mallocing=0?throwing=0?preemptoff=?locks=0?dying=0?spinning=false?blocked=false?lockedg=-1G1:?status=4(semacquire)?m=-1?lockedm=-1G2:?status=4(force?gc?(idle))?m=-1?lockedm=-1G3:?status=4(GC?sweep?wait)?m=-1?lockedm=-1G4:?status=4(GC?scavenge?wait)?m=-1?lockedm=-1G17:?status=1()?m=-1?lockedm=-1G18:?status=1()?m=-1?lockedm=-1G19:?status=1()?m=-1?lockedm=-1G20:?status=1()?m=-1?lockedm=-1G21:?status=1()?m=-1?lockedm=-1G22:?status=1()?m=-1?lockedm=-1G23:?status=1()?m=-1?lockedm=-1G24:?status=2()?m=3?lockedm=-1G25:?status=1()?m=-1?lockedm=-1G26:?status=1()?m=-1?lockedm=-1G27:?status=1()?m=-1?lockedm=-1G28:?status=1()?m=-1?lockedm=-1G29:?status=1()?m=-1?lockedm=-1G30:?status=1()?m=-1?lockedm=-1G31:?status=1()?m=-1?lockedm=-1G32:?status=1()?m=-1?lockedm=-1G33:?status=1()?m=-1?lockedm=-1G34:?status=2()?m=0?lockedm=-1G35:?status=1()?m=-1?lockedm=-1G36:?status=1()?m=-1?lockedm=-1 ...

該時(shí)刻的調(diào)度情況快照?qǐng)D示如下

我們可以根據(jù)詳細(xì)信息獲取到 P、M、G 的具體運(yùn)行情況。但需要注意的是,有一點(diǎn)我們不能確定,就是各個(gè) P 的 LRQ 與 GRQ 是哪些具體的 G 在隊(duì)列中等待,但這并不妨礙大局(因此,上圖中的 LRQ 和 GRQ 可能并不是實(shí)際的 G 編號(hào))。

總結(jié)

本文介紹了通過(guò)增加環(huán)境變量 GODEBUG ,我們可以在不做任何代碼改變或增加額外的插件情況下,方便地查看 Go 程序的調(diào)度情況。

讀者若想更直觀地理解 Go 語(yǔ)言的 GMP 和調(diào)度系統(tǒng),不妨一試 。

機(jī)器鈴砍菜刀

歡迎添加小菜刀微信

加入Golang分享群學(xué)習(xí)交流!

感謝你的點(diǎn)贊在看哦~

總結(jié)

以上是生活随笔為你收集整理的如何更直观地理解 Go 调度过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。