goroutine調度原理

goroutine簡介

golang語言作者Rob Pike說,“Goroutine是一個與其他goroutines 併發運行在同一地址空間的Go函數或方法。一個運行的程序由一個或更多個goroutine組成。它與線程、協程、進程等不同。它是一個goroutine“

  • goroutine通過通道來通信,而協程通過讓出和恢復操作來通信;
  • goroutine 通過Golang 的調度器進行調度,而協程通過程序本身調度;

簡單的說就是Golang自己實現了協程並叫做goruntine(本文稱Go協程),且比協程更強大。

goroutine調度原理

上面說到Go協程是通過Golang的調度器進行調度的,其中調度器的線程模型爲兩級線程模型。

有關兩級線程模型的介紹,可以看這篇文章

我們來看下Golang實現的兩級線程模型是怎樣的。首先要知道這三個字母代表的含義

  • M:代表內核級的線程
  • P:全程Processor,代表運行Go協程所需要的資源(上下文環境)
  • G:代表Go協程

    我們先看下爲實現調度Golang定義了這些數據結構存M,P,G
名稱 作用範圍 描述
全局M列表 Go的運行時 存放所有M的單向鏈表
全局P列表 Go的運行時 存放所有P的數組
全局G列表 Go的運行時 存放所有G的切片
調度器的空閒M列表 調度器 存放空閒M的單向鏈表
調度器的空閒P列表 調度器 存放空閒P的單向鏈表
調度器的自由G列表 調度器 存放自由G的單向鏈表(有兩個)
調度器的可運行G隊列 調度器 存放可運行G的隊列
P的自由G列表 本地P 存放當前P中自由G的單向鏈表
P的可運行G隊列 本地P 存放當前P中可運行G的隊列

然後從上往下解析Go的兩級線程模型圖

(1)M和內核線程之間是一對一的關係,一個M在其生命週期中,只會和一個內核線程關聯,所以不會出現對內核線程的頻繁切換;

Golang的運行時執行系統監控和垃圾回收等任務時候會導致創建M,M空閒時不會被銷燬,而是放到一個調度器的空閒M列表中,等待與P關聯,M默認數量爲10000

(2)P和M之間是多對多的關係,P和G之間是一對多的關係,他們的關聯是易變的,由Golang的調度器完成調度;

Golang的運行時按規則調度,讓P和不同的M建立或斷開關聯,使得P中的G能夠及時獲得運行時機

(3)P的數量默認爲CPU總核心數,最大爲256,當P沒有可運行的G時候(P的可運行G隊列爲空),P會被放到調度器的空閒P列表中,等待M與它關聯;

P有可能會被銷燬,如運行時用runtime.GOMAXPROCS把P的數量從32降到16時,剩餘16個會被銷燬,它們原來的G會先轉到調度器可運行的G隊列自由G列表

(4)每個P中有可運行的G隊列(如圖中最下面的那行G)和自由G列表(圖中未畫出來),當G的代碼執行完後,該G不會被銷燬,而是被放到P的自由G列表調度器的自由G列表。如果程序新建了Go協程,調度器會在自由G列表中取一個G,然後把Go協程的函數賦值到G中(如果自由G列表爲空,就創建一個G);

可見Golang調度器在調度時很大程度複用了M,P,G

(5)在Go程序初始化後,調度器首先進行一輪調度,此時用M去搜索可運行的G。其中我們的main函數也是一個G,找到可運行的G後就執行它;

至於怎麼找可運行的G呢?答案是到處找,想盡辦法找(這裏只列出一部分地方)。

  • 本地P的可運行的G隊列
  • 調度器的可運行的G隊列
  • 其他P的可運行的G隊列

(6)P的可運行G隊列最大隻能存放長度爲256的G,當隊列滿後,調度器會把一半的G轉到調度器的可運行G隊列

系統監控

上面大概描述了關於goroutine調度的流程。現在還存在一個問題,那就是當Go協程很多(併發量大)時候,顯然G是不能一直執行下去的,因爲也需要把執行機會留給其他的G。此時Golang運行時的系統監控就起作用了。
一般情況,當G運行時間超過10ms後,該G就會被系統告知需要停止了,讓其他G運行。(這裏情況比較複雜,並不能確保每個G都能被公平執行)

以下特殊情況該G不需要停止

  • P的可運行G隊列爲空(沒有其他G可運行)
  • 有空閒的M在尋找可運行的G(沒有其他G可運行)
  • 空閒的P(還有P閒着)

總結

Golang以兩級線程實現模型,自己實現goruntine和調度器,優勢在於並行和非常低的資源使用。

主要體現:

  • 內存消耗方面(每個Go協程佔的內存遠小於線程佔的內存)
  • 切換(調度)開銷方面
  • 線程切換涉及模式切換(從用戶態切換到內核態)

此外,Go協程執行任務完成的順序並不都是按我們預期的那樣(程序不加以控制的情況下),特別在一些耗時較長的任務中。且每個Go協程執行的時間也不是絕對公平的。

文章轉自:https://www.cnblogs.com/FireworksEasyCool/p/11508806.html

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