亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

調度器是怎么處理核上任務分配的?

 

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

?? 這篇文章基于 Go 1.13 版本。

在 Go 中創建 gorotine 既方便又快捷,然而 Go 在同一時間內最多在一個核上運行一個 gorotine,因此需要一種方法來存放其他的 gorotine,從而確保處理器(processor)負載均衡。

Goroutine 隊列

Go 使用兩級隊列來管理等待中的 goroutine,分別為本地隊列和全局隊列。每一個處理器都擁有本地隊列,而全局隊列是唯一的,且能被所有的處理器訪問到:

調度器是怎么處理核上任務分配的?

 

Global and local queues

每個本地隊列都有最大容量,為 256。在容量滿了之后,任意新到來的 Goroutine 都會被放置到全局隊列。下面的例子是,生產了上千個 Goroutine 的程序:

func main() {
   var wg sync.WaitGroup

   for i := 0;i < 2000 ;i++ {
      wg.Add(1)
      Go func() {
         a := 0

         for i := 0; i < 1e6; i++ {
            a += 1
         }

         wg.Done()
      }()
   }

   wg.Wait()
}

下面是擁有兩個處理器的調度器追蹤數據(traces):

調度器是怎么處理核上任務分配的?

 

Details of the local and global queues

追蹤數據通過 runqueue 展示了全局隊列中 Goroutine 的數量,以及方括號中 [3 256] 的本地隊列 goroutine 數量(分別為 P0 和 P1)。當本地隊列滿了,積壓了 256 個等待中的 goroutine 后,下一個 Goroutine 會被壓棧到全局隊列中,正如我們從 runqueue 看到的數量增長一樣。

Goroutine 僅在本地隊列滿載之后才會加入到全局隊列;它也會在 Go 往調度器中批量注入時被加到全局隊列,例如,網絡輪詢器(network poller) 或者在垃圾回收期間等待的 goroutine。

下面是上一個例子的圖示:

調度器是怎么處理核上任務分配的?

 

Local queues have up to 256 goroutines

不過,我們還想知道,為什么本地隊列 P0 在上一個列子中不為空。因為 Go 使用了其他策略確保每個處理器都有任務處理。

任務竊取

如果處理器沒有任務可處理,它會按以下規則來執行,直到滿足某一條規則:

  • 從本地隊列獲取任務
  • 從全局隊列獲取任務
  • 從網絡輪詢器獲取任務
  • 從其它的處理器的本地隊列竊取任務

在我們前面的例子中,主函數在 P1 上運行并創建 goroutine。當第一批 gourinte 已經進入了 P1 的本地隊列時,P0 正在尋找任務。然而,它的本地隊列,全局隊列,以及網絡輪詢器都是空的。最后的解決方法是從 P1 中竊取任務。

調度器是怎么處理核上任務分配的?

 

Work-stealing by P0

下面是調度器在發生任務竊取前后的追蹤數據:

調度器是怎么處理核上任務分配的?

 

Work-stealing by P0

追蹤數據展示了,處理器是如何從其它處理器中竊取任務的。它從(其他處理器的)本地隊列中取走一半的 goroutine;在七個 Goroutine 中,偷走了四個 —— 其中一個立馬在 P0 執行,剩下的放到本地隊列。現在處理器間工作處于負載良好的狀態。這能通過執行 tracing 來確認:

調度器是怎么處理核上任務分配的?

 

goroutine 被合理地分發,然后因為沒有 I/O,goroutine 被鏈式執行而不需要切換。我們現在看一下,當出現例如涉及到文件操作等 I/O 時,會發生什么。

I/O 與全局隊列

一起看下涉及到文件操作的例子:

func main() {
   var wg sync.WaitGroup

   for i := 0;i < 20 ;i++ {
      wg.Add(1)
      Go func() {
         a := 0
         for i := 0; i < 1e6; i++ {
            a += 1
            if i == 1e6/2 {
               bytes, _ := ioutil.ReadFile(`add.txt`)
               inc, _ := strconv.Atoi(string(bytes))
               a += inc
            }
         }
         wg.Done()
      }()
   }

   wg.Wait()
}

變量 a 隨著時間以文件的字節數增加,下面是新的追蹤數據:

調度器是怎么處理核上任務分配的?

 

在這個例子中,我們能看到每一個 Goroutine 不只被一個處理器處理。在系統調用的情況下,當調用完成后,Go 使用網絡輪詢器從全局隊列中把 gouroutine 取回來。這里是 Goroutine #35 的一個示意圖:

調度器是怎么處理核上任務分配的?

 

I/O operations put the work back to the global queue

當一個處理器能從全局隊列中獲取任務,第一個可用的處理器( P) 會執行這個 goroutine。這個行為解釋了,為什么一個 Goroutine 能在不同的處理器中運行,也展示了 Go 是如何讓空閑的處理器資源運行 goroutine,從而進行系統調用的優化。


via: https://medium.com/a-journey-with-go/go-work-stealing-in-go-scheduler-d439231be64d

作者:Vincent Blanchon[1]譯者:LSivan[2]校對:polaris1119[3]

本文由 GCTT[4] 原創編譯,Go 中文網[5] 榮譽推出

參考資料

[1]

Vincent Blanchon: https://medium.com/@blanchon.vincent

[2]

LSivan: https://github.com/LSivan

[3]

polaris1119: https://github.com/polaris1119

[4]

GCTT: https://github.com/studygolang/GCTT

[5]

Go 中文網: https://studygolang.com/

分享到:
標簽:調度
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定