首頁  >  文章  >  後端開發  >  Go語言中的協程調度器詳解

Go語言中的協程調度器詳解

王林
王林原創
2023-06-05 20:40:321633瀏覽

Go語言自帶了一個高效率的協程調度器,可以輕鬆處理並發任務,實現高效能的程式。在本文中,我們將深入了解Go語言中的協程調度器,並探討其實作、操作以及最佳化。

協程簡介

協程是一種輕量級的執行緒或稱為使用者狀態執行緒。它由程式設計師調度,而不是由作業系統調度。協程的特徵是非搶佔式,即只有在明確呼叫yield()函數時才會切換上下文。因此,協程的切換開銷非常小,可以輕鬆地建立和銷毀,而且可同時執行非常多的協程,以實現並發執行程式。

Go語言協程模型

Go語言採用的是M:N 協程模型,也就是多個使用者狀態執行緒 M,對應多個系統級執行緒 N 的關係。這種模型充分發揮了多核心CPU的優勢,同時減少了上下文的切換開銷,並提高了調度效能。

M表示作業系統線程,即物理線程,是作業系統調度的最小單位。而N則表示Go語言運行時系統(runtime)中的虛擬執行緒(goroutine),是實現並發的最小單位。 N個goroutine 會映射到M個執行緒上,在運行時由調度器調度。

協程調度器

協程調度器是Go語言執行時間系統中的核心元件,負責管理並調度多個協程執行任務。它是一個高等級的調度器,可以控制協程的運作和切換,實現協程的等級調度。在Go語言中,協程調度器額外使用了一種成為Goroutine的運作實體,可以更有效率地在協程中切換執行任務。

協程調度器實現原理

協程調度器實現的原理可以分為兩個層次:作業系統層面和Go語言運行時系統層面。

作業系統層面

作業系統層面上,協程調度器會在執行時間映射多個使用者執行緒到多個作業系統執行緒上,利用多核心CPU的平行運算能力。

Go語言協程模型中的M:N架構,即M表示作業系統執行緒(Machine),N表示Go語言的虛擬執行緒(N,代表Goroutine),在運行時由調度器管理調度。調度器的主要作用就是在每個作業系統執行緒上維護一個調度任務佇列,根據任務佇列中任務的優先權和調度演算法動態調度各個執行緒上的任務的執行,並管理執行緒資源。

Go語言運行時系統層面

在Go語言執行時間系統層面上,協程調度器使用了三種機制:調度器、調度器佇列和P。

調度器

Go語言的協程調度器由一個全域的調度器控制,它會維護調度器佇列、P佇列、自旋次數、調度演算法等。調度器會動態管理每個執行緒上的任務執行,以實現最佳化協程的執行效率。

調度器佇列

調度器佇列是調度器用來記錄所有等待調度的 Goroutine 的地方。在調度器將Goroutine 分配到P 上時,它會首先從隊列中尋找等待調度的Goroutine,如果找到了,則立即把它們放入P 的本地隊列,如果沒有找到,則新創建一個Goroutine並放到P的本地佇列中。

P

P 是一個處理器,用來執行 Goroutine,它所擁有的佇列就是本地佇列。 P 的數量由 GOMAXPROCS 環境變數所控制,如果不設置,Go程式預設使用機器的核心數。

Go調度器的最佳化

Go調度器有許多最佳化策略,以下是其中幾個:

  1. Work Stealing
# #當某個P隊列內的Goroutine中都被阻塞時,Go調度器會尋找其它P隊列中的Goroutine然後偷走一些放到自己隊列去運行。這種策略保證了所有P的穩定負載和均負載。

    Preemption
Goroutine可以在執行的時候為自己設定計時器,當時間到了之後呼叫 runtime.Goexit,告訴 runtime 這個 Goroutine 可以主動調度了。如果 goroutine 沒有主動地呼叫 Goexit,Go調度器也有一種預搶佔策略。在 Go 1.13 之前,只有在 GOMAXPROCS 為 1 的時候才能實現預搶佔。現在已經升級支援更多情況下。

    Local Runqueue
為了減少不同執行緒之間任務的爭搶,每個執行緒都會有一個自己的本地佇列,每個執行緒優先從本地佇列中取任務執行,只有本機佇列為空時才會去全域佇列中取得任務。

總結

協程調度器是Go語言高效能並發的關鍵元件之一。它負責管理並調度多個協程執行任務,採用的是M:N協程模型,在作業系統層面和Go語言運行時系統層面使用不同的機制和演算法來確保協程的高效執行和調度。同時,Go調度器還有許多最佳化策略,例如協程搶佔、局部運行佇列以及任務竊取等,可以幫助程式更有效率地運行,提高程式效能和吞吐量。

以上是Go語言中的協程調度器詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn