Golang GMP模型

Golang GMP模型

GMP 是 Go 語言運行時(runtime)中的一個重要組件,它是 Go 語言的調度模型。GMP 模型使用三種不同的線程來處理 Go 程序:Goroutine、M(Machine)和 P(Processor)。在 GMP 模型中,Goroutine 是實際編寫的程序代碼,M 是 Go 語言的內部線程,P 則負責管理 M 和 Goroutine 之間的調度。

解釋一下 GMP 模型的工作原理:

GMP 模型的核心是三個概念:G、M 和 P。

  • G:Goroutine是Go語言中的輕量級協程,它可以被看作是一種用戶態的線程,能夠在單個線程上模擬出多個線程的併發執行效果。Goroutine的調度由M和P共同協作完成。

  • M:Machine是操作系統線程的簡稱,它是Go語言實現協程調度的實際執行者。每個M都有一個Goroutine隊列,以及一個P調度器,用於管理並調度Goroutine。M的數量可以通過GOMAXPROCS環境變量進行配置,默認爲CPU核心數。

  • P:Processor是調度器的簡稱,它負責將Goroutine綁定到M線程上,並將Goroutine放入隊列中,等待M線程運行。每個P都有一個Goroutine隊列,以及一個M調度器,用於管理並調度M線程。P的數量是由Go運行時自動根據需要進行調整的。

GMP模型的本質是將一組Goroutine分配到一組M線程中,通過P調度器來管理並調度它們的執行。當一個Goroutine被創建時,它會首先被放入到P的隊列中,等待M線程來執行。M線程會從P的隊列中取出一個Goroutine,並將其執行,如果執行過程中發生阻塞,M線程會放棄該Goroutine的執行,並將其重新放回到P的隊列中,等待後續的調度。

在GMP模型中,調度器P有兩個重要的任務,一是負責調度M線程的執行,二是負責調度Goroutine的執行。P會通過兩個隊列來分別管理M線程和Goroutine,M線程隊列中存儲等待調度的M線程,Goroutine隊列中存儲等待調度的Goroutine。P會按照一定的調度算法,從M線程隊列中選取一個M線程,並將其綁定到一個Goroutine上執行。

具體來說,Goroutine 是 Go 語言中的併發基本單元,一個 Goroutine 類似於一條輕量級的線程,它由 Go 運行時負責調度和管理。Goroutine 是 Go 語言的一大特色,因爲它具有極低的啓動和銷燬成本,一個 Go 程序可以同時創建數百萬個 Goroutine,而這些 Goroutine 的調度則由 Go 運行時自動進行,無需程序員手動管理。

M 是 Go 運行時對操作系統線程的抽象,每個 M 負責管理一條操作系統線程以及其中運行的 Goroutine。每個 M 與一個或多個 P 相關聯,P 是 Goroutine 調度器,它負責在 M 上運行 Goroutine,並將其調度到其他 M 上執行。每個 P 都有一個隊列,用於存放可運行的 Goroutine。

P 由調度器創建,並且與 M 綁定。P 的數量可以通過 GOMAXPROCS 環境變量設置。當一個 Goroutine 準備就緒後,調度器會將其加入到某個 P 的隊列中,P 就會負責運行這個 Goroutine,直到其執行完畢或者被阻塞。

總的來說,GMP 模型實現了一個三層的調度器,其中最上層是 Goroutine 調度器,用於調度 Goroutine;第二層是 P 調度器,用於將可運行的 Goroutine 調度到某個 P 上執行;第三層是 M 調度器,用於將 P 調度到某個 M 上運行。

在 GMP 模型中,調度器的核心是 Work-stealing 調度算法。這個算法可以保證 Goroutine 在不同 P 上的負載均衡,並且能夠充分利用多核 CPU 的性能。

在實踐中,GMP 模型讓 Go 語言具有了出色的併發性能和擴展性。程序員只需要編寫簡單的 Goroutine 代碼,就可以充分利用多核 CPU 併發執行任務。

總的來說,GMP模型通過將Goroutine分配到一組M線程中,並由P調度器管理和調度,實現了高效的協程調度。Goroutine通過輕量級的棧和調度器管理,大大提高了程序的併發能力和執行效率。

GMP 模型的設計目標是充分利用多核 CPU,提高併發程序的性能。具體來說,GMP 模型可以通過以下幾種方式實現:

  1. 多線程執行:GMP 模型中的 M 可以同時運行多個 Goroutine,充分利用多核 CPU 的計算能力。
  2. 多態調度:P 可以將 Goroutine 分配給任意一個 M,實現了多態調度,充分利用了計算資源。
  3. 伸縮性:GMP 模型可以根據系統的負載情況動態調整 M 和 P 的數量,實現伸縮性。

下面是一個簡單的 GMP 模型的例子,演示瞭如何使用 GMP 模型實現併發處理任務:

package main

import (
	"fmt"
	"runtime"
	"sync"
)

func main() {
	runtime.GOMAXPROCS(1) // 設置使用一個處理器核心
	var wg sync.WaitGroup // 定義一個同步等待組
	wg.Add(2)             // 有兩個任務需要完成

	fmt.Println("Start Goroutines")

	go func() { // 啓動一個新的 goroutine
		defer wg.Done() // 在函數退出時調用 wg.Done(),通知等待組一個任務已完成
		for count := 0; count < 3; count++ {
			for char := 'a'; char < 'a'+26; char++ {
				fmt.Printf("%c ", char)
			}
			fmt.Println()
		}
	}()

	go func() { // 啓動另一個 goroutine
		defer wg.Done() // 在函數退出時調用 wg.Done(),通知等待組一個任務已完成
		for count := 0; count < 3; count++ {
			for char := 'A'; char < 'A'+26; char++ {
				fmt.Printf("%c ", char)
			}
			fmt.Println()
		}
	}()

	fmt.Println("Waiting To Finish")
	wg.Wait() // 等待所有 goroutine 完成

	fmt.Println("\nTerminating Program")
}

Work-stealing 調度算法

package main

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

func main() {
	numCPUs := runtime.NumCPU() // 獲取可用處理器核心數
	runtime.GOMAXPROCS(numCPUs) // 設置使用所有處理器核心

	work := make(chan int, numCPUs) // 創建一個帶有緩衝的int類型通道

	var wg sync.WaitGroup // 定義一個同步等待組

	for i := 0; i < numCPUs; i++ {
		wg.Add(1) // 爲每個處理器核心增加一個任務
		go func() { // 啓動每個處理器核心
			defer wg.Done()
			for {
				select {
				case job, ok := <-work: // 從通道中獲取工作
					if ok {
						fmt.Println("Worker", i, "processing job", job)
						time.Sleep(time.Second) // 模擬工作時間
					} else {
						fmt.Println("Worker", i, "shutting down")
						return
					}
				default: // 如果通道中沒有工作,則尋找其他處理器核心的閒置工作
					runtime.Gosched()
				}
			}
		}()
	}

	for i := 0; i < numCPUs*2; i++ { // 向通道中添加工作
		work <- i
	}

	close(work) // 關閉通道,表示所有工作都已完成

	wg.Wait() // 等待所有處理器核心完成任務

	fmt.Println("All work complete")
}

在此示例中,首先使用runtime.NumCPU()獲取可用的處理器核心數,並使用runtime.GOMAXPROCS()將所有處理器核心設置爲可用狀態。創建了一個帶有緩衝的通道,大小爲可用的處理器核心數,以便可以將工作項分發給多個處理器核心。使用sync.WaitGroup來等待所有處理器核心完成任務。在for循環中,爲每個處理器核心啓動一個goroutine,每個goroutine使用select語句從通道中獲取工作。如果通道中有工作,則處理工作,否則通過runtime.Gosched()在處理器核心之間進行工作竊取。在主函數中,向通道中添加工作,並在完成所有工作後關閉通道。最後,調用wg.Wait()等待所有處理器核心完成任務,並打印"All work complete"表示所有工作都已完成。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章