建立系統執行緒以及在系統執行緒間切換,會對程式的記憶體和效能造成較大的開銷。為了達到這個目標,go 的目標是盡量利用 cpu 多核資源。設計之初就考慮了高併發性。
go
擁有乙個將協程排程到系統執行緒執行的排程器。
這個排程器定義了三個核心概念,在go
原始碼中是這樣解釋的:
以下是m
必須有乙個相關聯的p
才能執行go
**。
p,m,g
模型的示意圖:
每個協程(g
)在乙個分配給邏輯處理器(p
)的系統執行緒(m
)上執行。首先,go
會根據當前機器的邏輯cpu
個數來建立相應數量的p
,並將它們存放在一張空閒p
列表中然後,新建立並等待被執行的 goroutine 協程會喚醒乙個p
來執行這個任務,這個p
會建立乙個和系統核心級執行緒相關聯的使用者級執行緒m
和p
一樣,如果乙個m
沒有工作可做了,該m
會被放入空閒m
鍊錶中在程式啟動時,以上,我們有了一張管理協程和核心執行緒的全域性圖,讓我們進一步看看go
會預先建立一些核心級執行緒
以及相關聯的使用者級執行緒m
。在上面的小例子中,第乙個列印
hello
的協程會使用主協程,而第二個列印world
的協程會從空閒列表中獲取到乙個m
和乙個p
go
在什麼情況下會使用更多的m
和p
,以及系統呼叫時協程是如何被管理的。
go
對系統呼叫做了優化,具體做法是在執行時對系統呼叫做了封裝(不管系統呼叫是否會造成阻塞)。該部分封裝**會自動將上下文環境
p
與使用者執行緒m
解除繫結,使得另乙個使用者執行緒m
可以在這個p
上執行。讓我們來看乙個讀取檔案的例子:
以下是開啟檔案的流程:func
main()
g
執行系統呼叫,p0
被放入空閒列表中,可被使用。當系統呼叫結束之後,
go
順序執行如下流程直到其中一條規則被滿足:試圖獲取同乙個
p
,在我們上面的例子就是p0
,如果獲取到,則恢復執行。試圖在空閒列表中獲取乙個
p
,如果獲取到,則恢復執行。將
g
(協程)放入全域性佇列中,將相關的m
放入空閒列表中。
go
使用非阻塞i/o
模式,對資源還沒有就緒的情況也做了處理,比如說http
請求。這種情況下首先也遵循上面所說的系統呼叫的流程,之後如果底層的系統呼叫由於資源沒有就緒而返回失敗時,
go
會強制使用network poller
,並且將該協程掛起。以下是例子:
當使用了系統呼叫時,go
並不限制這些可能被阻塞的系統執行緒的數量,以下是go
**中的注釋說明:以下是乙個例子gomaxprocs
變數限制的是使用者層面go
**的系統執行緒數量。對於可能造成阻塞的系統呼叫的執行緒數是不做限制的;它們不計算在
gomaxprocs
限制之中。func
main()
()} wg.
wait()
}
值得一提,由於以下是使用go
可以復用核心執行緒,所以工具檢視到的執行緒數要小於例子中for
迴圈的次數。tracing
工具,檢視程式建立的執行緒數量:100
個協程被對映到了2
個執行緒上go語言之goroute協程
goroute協程 程序和執行緒 程序是系統進行資源分配和排程的基本單位,執行緒是cpu排程和發派的基本單位,乙個程序可以建立和撤銷多個執行緒 併發和並行 多執行緒程式在乙個核的cpu上面執行,是併發 多執行緒程式在多個核的cpu上面執行,這是並行 協程和執行緒 協程 獨立的棧空間,共享的堆記憶體,...
執行緒程序以及協程的區別
程序,儲存在硬碟上的程式執行之後,會在記憶體裡形成乙個獨立的記憶體體,這個記憶體體有自己獨立的位址空間,有自己的堆,上級掛靠單位是作業系統,作業系統會以程序為單位分配系統資源 cpu時間片,記憶體等資源 程序是資源分配的最小單位。執行緒也成為輕量級執行緒,是作業系統排程 cpu排程 執行的最小單位 ...
Go語言學習筆記 Go協程
併發 concurrency 是指一次處理大量事情的能力。讓我們用乙個 例子來說明。並行 parallelism 指的是同時處理多個事情。雖然聽起來像併發,但是它們是不同的。go 原生支援併發。在go中,使用 go 協程 goroutine 和通道 channel 來處理併發。函式 main 就以 ...