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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

聊聊 g0

發布時間:2024/4/11 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聊聊 g0 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

很多時候,當我們跟著源碼去理解某種事物時,基本上可以認為是以時間順序展開,這是編年體的邏輯。還有另一種邏輯,紀傳體,它以人物為中心編排史事,使得讀者更聚焦于某個人物。以一種新的視角,把所有的事情串連起來,令人大呼過癮。今天我們試著以這樣一種邏輯再看 g0。

回顧一下 Go 夜讀第 78 期,關于調度器源碼分析的內容。我們講過,與主線程綁定的 M 對應的 g0 的主要作用是提供一個比一般 goroutine 要大的多棧(64K)供 runtime 代碼執行。

初始化的過程中,在函數 runtime·rt0_go 里會給主線程的 g0 分配棧空間:

g0 棧空間

之后,主線程會與 m0 綁定,m0 又與 g0 綁定:

主線程綁定 m0,g0

之后,又與 p0 綁定:

g0-p0-m0

這樣,主線程的這一套 GPM 就可以轉起來了。接著,就創建了 main goroutine,放入 p0 的本地待運行隊列。最后,通過 schedule() 函數進入調度循環。

前面說的是程序初始化的過程中,g0 是如何誕生的。當執行到 main.main() 函數,也說是用戶在 main 包下寫的 main 函數里,我們隨手一句:

go func() {// 要做的事 }()

就啟動了一個 goroutine 時,在 Go 編譯器的作用下,最終會轉化成 newproc 函數。在 newproc 函數的內部,會在 g0 棧上調用 newproc1 函數,完成后續的工作。創建完成后,會將新創建的 goroutine 放入 _p_ 的本地待運行隊列。

因為新增加了一個 g,這時會嘗試去喚醒一個 P 來一起執行任務。判斷條件是:

if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 && mainStarted {wakep() }

即在有空閑 P 以及沒有正在“找工作的 M”的情況下,才會嘗試去喚醒一個 P。我們又知道,其實 P 的數量在程序運行過程中一般不會變化,所以這里所謂的喚醒其實就是把空閑的 P 利用起來。

通過 wakep() -> startm() -> newm() -> allocm() -> malg() 這條鏈路創建 g0,這里 g0 的棧大小實際上為 8KB。

mp.g0 = malg(8192 * sys.StackGuardMultiplier) // sys.StackGuardMultiplier 在 linux 里為 1

g0 作為一個特殊的 goroutine,為 scheduler 執行調度循環提供了場地(棧)。對于一個線程來說,g0 總是它第一個創建的 goroutine。之后,它會不斷地尋找其他普通的 goroutine 來執行,直到進程退出。

當需要執行一些任務,且不想擴棧時,就可以用到 g0 了,因為 g0 的棧比較大。g0 其他的一些“職責”有:創建 goroutine、deferproc 函數里新建 _defer、垃圾回收相關的工作(例如 stw、掃描 goroutine 的執行棧、一些標識清掃的工作、棧增長)等等。

因為 g0 這樣一個特殊的 goroutine 所做的工作,使得 Go 程序運行地更快。

注:最近在 medium 上看到了一個非常贊的關于 Go 的博客博客[1],題圖畫得很有閱讀的欲望。這篇文章也是參考于其中的一篇[2]

References

[1]?博客:?https://medium.com/a-journey-with-go
[2]?其中的一篇:?https://medium.com/a-journey-with-go/go-g0-special-goroutine-8c778c6704d8

總結

以上是生活随笔為你收集整理的聊聊 g0的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。