go語言併發之MPG模型

請記住go併發的真理:

Do not communicate by sharing memory; instead, share memory by communicating.

不要以共享內存的方式來通信,相反,要通過通信來共享內存。

go語言天生的併發大家都知道,可是go是如何實現輕鬆的構造上萬的協程呢?今天我們就說一下go併發的MPG模型。

後續會有更多的模式和算法以及區塊鏈相關的,如果你是想學習go語言或者是對設計模式或者算法感興趣亦或是區塊鏈開發工作者,都可以關注一下。(微信公眾號:Go語言之美,更多go語言知識信息等)。公眾號會持續為大家分享更多幹貨。

  1. M 代表著一個內核線程,也可以稱為一個工作線程。goroutine就是跑在M之上的
  2. P 代表著(Processor)處理器 它的主要用途就是用來執行goroutine的,一個P代表執行一個Go代碼片段的基礎(可以理解為上下文環境),所以它也維護了一個可運行的goroutine隊列,和自由的goroutine隊列,裡面存儲了所有需要它來執行的goroutine。
  3. G 代表著goroutine 實際的數據結構(就是你封裝的那個方法),並維護者goroutine 需要的棧、程序計數器以及它所在的M等信息。
  4. Seched 代表著一個調度器 它維護有存儲空閒的M隊列和空閒的P隊列,可運行的G隊列,自由的G隊列以及調度器的一些狀態信息等。
go語言併發之MPG模型

多個goroutine併發合作

上面這個圖生動的說明多個協程工作形式,其中每一個gopher(土撥鼠)可以看作一個協程(G),其實對於這些gopher,還有一個包工頭的gopher,他來管理這些工作的gopher,這個包工頭就可以看作一個 Seched。

go語言併發之MPG模型

MPG

我們在看上面這個圖,圖中P正在執行的Goroutine為藍色的,處於待執行狀態的Goroutine為灰色的,灰色的Goroutine形成了一個隊列runqueues。

我們再看一下三者的宏觀圖:

go語言併發之MPG模型

MPG宏觀圖

在這裡,當一個P關聯多個G時,就會處理G的執行順序,就是併發,當一個P在執行一個協程工作時,其他的會在等待,當正在執行的協程遇到阻塞情況,例如IO操作等,go的處理器就會去執行其他的協程,因為對於類似IO的操作,處理器不知道你需要多久才能執行結束,所以他不回去等你執行完。

上面我們看著go的併發好像是搶佔式的,事實上go的協程是非搶佔式的,由協程主動交出控制權,也就是說,上面在發生IO操作時,並不是調度器強制切換執行其他的協程,而是當前協程交出了控制權,調度器才去執行其他協程。我們列舉一下goroutine可能切換的點:

  • I/O,select
  • channel
  • 等待鎖
  • runtime.Gosched()

這些點是go協程可能切換的地方,但是並不是一定切換的。

正是因為是非搶佔式的,所以才輕鬆的構造上萬的協程,如果是搶佔式,那麼就會在切換任務時,保存當前的上下文環境,因為當前線程如果正在做一件事,做到一半,我們就強制停止,這時我們就必須多保存很多信息,避免再次切換回來時任務出錯。

線程是操作系統層面的多任務,而go的協程屬於編譯器層面的多任務,go有自己的調度器來調度。一個協程在哪個線程上是不確定的,這個是由調度器來決定的,多個協程可能在一個或多個線程上運行。

go的併發是很重要的,這裡只是簡單說一下MPG模型的個人理解,如果大家有不同意見,可以一起討論學習,三人行必有我師。如果覺得這篇文章不錯可以轉發(微信公眾號:Go語言之美,更多go語言知識信息等)。


分享到:


相關文章: