Goroutine的調度分析(一)

  golang這個新興的語言,最關鍵的就在於goroutine,而goroutine的調度又是golang的核心。可以說,沒有goroutine,那麼這個語言就會毫無意義,沒有發明的必要。爲了能夠更好的寫出高質量的代碼,最近學習了goroutine的調度,收穫良多。寫篇文章總結記錄一下。

我的參考資料

Analysis of the Go runtime scheduler 一篇分析goroutine的論文,英文的,其實這篇論文寫遠比很多博客來的通俗易懂,值得一看。
How Goroutines Work這篇博客簡略寫goroutine和線程的區別,文章底部也有更進一步閱讀參考的鏈接
goroutine與調度器圖文並茂的講了goroutine調度的算法。值得一看。

Go RUNTIME

  Go Runtime 管理着goroutine的調度以及運行時的垃圾回收,而我們今天所討論主要是goroutine的調度。
  Go程序會被編譯成機器碼,因爲Go提供了,goroutine、channels、垃圾回收,所以就需要一個runtime的框架來支持這些特性。Go 程序可以被看成兩層,一層是用戶代碼,一層是runtime並且是調用一些管理goroutine, channel, 以及一些其他的高層抽象。任何系統調用都要通過runtime層來配合goroutine的調度。下圖展示了go程序、Go runtime、以及操作系統之間的關係。
這裏寫圖片描述
  runtime記錄着每一個goroutine的狀態,並且會在一個線程池上來調度這些goroutine。goroutine是和線程分離的但是卻需要依靠線程來運行。所以,有效地在線程池上調度goroutine對go程序的運行效率就顯得非常重要了。

線程和goroutine的區別

內存的消耗

  goroutine的創建是不需要的很多內存的,大約2KB棧空間而已,而一個線程一創建就要約1MB內存,一個服務器一個請求創建一個goroutine而沒有任何問題,而一個請求創建一個線程則會導致OutOfMemoryError,任何語言用多線程來實現併發都會遇到這個問題。

創建與銷燬的代價

  線程的創建與銷燬代價是比較大的,所以往往弄一個線程池來解決這個問題。而goroutine的創建銷燬都比較cheap, 當然,其實可以看成go已經實現了線程池。

切換代價

  當線程阻塞,其他的線程必須被調度過來被阻塞線程的位置,當線程切換,調度器需要保存所有的寄存器,通用寄存器、程序計數器、棧指針還有其他一些亂七八槽的寄存器,這樣的切換代價是很高的,尤其是在頻繁進行線程切換的情況下。
  而goroutine的切換代價就很低了,只需要保存3個寄存器:程序計數寄存器、棧指針以及DX。所以,goroutine調度的切換代價以及時間是可以忽略不計的。

goroutine是怎麼執行的

  runtime管理調度着所有的goroutine,從出生到死亡。它會分配一些線程,採用多路複用的策略,來執行goroutine。在任何時候,一個線程會執行一個goroutine,如果這個goroutine阻塞了,這個goroutine就會被換出,這個線程就會執行其他的goroutine。因爲goroutine是合作式的調度(這裏我也不太明白),那麼如果一個goroutine不停的循環就會餓死其他的在這個線程上的goroutine。在go1.2中,這個問題已經有所緩解,當進入一個函數後,runtime會不定時的激活調度器,所以一個沒有內聯函數的循環會被取代。

goroutine阻塞

  goroutine是輕量級的,並且以下原因中不會造成線程阻塞。

1. 網絡輸入
2. sleeping
3. channel 操作
4. 通過sync包的阻塞操作

即使產生上萬的goroutine,如果它們是以上4種原因阻塞的,也不會造成系統資源的浪費,因爲runtime會調度其他的goroutine給這些被多路複用的thread執行。
簡單來說,goroutine是在線程之上的輕量級抽象,go的使用者不用解決線程的麻煩,而系統也不會感受到goroutine的存在。

線程和處理器

  儘管你不能直接控制runtime創造線程的數量,但是你可以設置系統使用的處理器的核的數量。通過設置GOMAXPROCS,你就可以增加或減少核的數量來改善你程序的性能了。

思考

  和其他語言一樣,避免同時操作共享的內存是很重要的,最好的策略是用channel來實現共享,do not cmmunicate by sharing memory; instead, share memory by communicating.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章