弄懂goroutine排程原理

2022-01-15 01:34:22 字數 2312 閱讀 7925

golang語言作者rob pike說,「goroutine是乙個與其他goroutines 併發執行在同一位址空間的go函式或方法。乙個執行的程式由乙個或更多個goroutine組成。它與執行緒、協程、程序等不同。它是乙個goroutine「

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

上面說到go協程是通過golang的排程器進行排程的,其中排程器的執行緒模型為兩級執行緒模型。

有關兩級執行緒模型的介紹,可以看這篇文章

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

名稱作用範圍

描述全域性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呢?答案是到處找,想盡辦法找(這裡只列出一部分地方)。

(6)p的可執行g佇列最大只能存放長度為256的g,當佇列滿後,排程器會把一半的g轉到排程器的可執行g佇列

上面大概描述了關於goroutine排程的流程。現在還存在乙個問題,那就是當go協程很多(併發量大)時候,顯然g是不能一直執行下去的,因為也需要把執行機會留給其他的g。此時golang執行時的系統監控就起作用了。

一般情況,當g執行時間超過10ms後,該g就會被系統告知需要停止了,讓其他g執行。(這裡情況比較複雜,並不能確保每個g都能被公平執行)

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

golang以兩級執行緒實現模型,自己實現goruntine和排程器,優勢在於並行和非常低的資源使用。

主要體現:

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

如有錯誤地方,還請狂噴!

Goroutine的排程模型

當前有兩個p,各自繫結了乙個m,每個p上掛了乙個本地goroutine佇列,也有乙個全域性goroutine佇列。流程 每次使用go關鍵字宣告時,乙個g物件被建立並加入到本地g佇列或者全域性g佇列。檢查是否有空閒的p 處理器 若有那麼建立乙個m 若有正在sleep的m那麼直接喚醒它 與其繫結,然後這...

Goroutine的排程分析 一

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

golang的goroutine排程機制

感覺豁然開朗,受益匪淺 去繁就簡,再加上自己的一些理解,整理了一下 排程器 主要基於三個基本物件上,g,m,p 定義在原始碼的src runtime runtime.h檔案中 1.g代表乙個goroutine物件,每次go呼叫的時候,都會建立乙個g物件 2.m代表乙個執行緒,每次建立乙個m的時候,都...