偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Go Scheduler 的 GMP 模型

開發(fā)
Go 為了自身 goroutine 執(zhí)行和調(diào)度的效率,自身在 runtime 中實現(xiàn)了一套 goroutine 的調(diào)度器。

寫在前面

Go 為了自身 goroutine 執(zhí)行和調(diào)度的效率,自身在 runtime 中實現(xiàn)了一套 goroutine 的調(diào)度器,下面通過一段簡單的代碼展示一下 Go 應(yīng)用程序在運(yùn)行時的 goroutine,方便大家更好的理解。

The Go scheduler is part of the Go runtime, and the Go runtime is built into your application

for i := 0; i < 4; i++ {
go func() {
time.Sleep(time.Second)
}()
}
fmt.Println(runtime.NumGoroutine())

上面這段代碼的輸出為:5。說明當(dāng)前這個應(yīng)用程序中存在 goroutine 的數(shù)量是 5,事實上也符合我們的預(yù)期。那么問題來了,這 5 個 goroutine 作為操作系統(tǒng)用戶態(tài)的基本調(diào)度單元是無法直接占用操作系統(tǒng)的資源來執(zhí)行的,必須經(jīng)過內(nèi)核級線程的分發(fā),這是操作系統(tǒng)內(nèi)部線程調(diào)度的基本模型,根據(jù)用戶級線程和內(nèi)核級線程的對應(yīng)關(guān)系可以分為 1 對 1,N 對 1 以及 M 對 N 這三種模型,那么上述的 5 個 goroutine 在內(nèi)核級線程上是怎么被分發(fā)的,這就是 Go語言的 goroutine 調(diào)度器決定的。

圖片

GMP 模型

整個 goroutine 調(diào)度器的實現(xiàn)基于 GMP 的三級模型來實現(xiàn)。

  • G:goroutine
  • M:內(nèi)核級線程,運(yùn)行在操作系統(tǒng)的核心態(tài)。在 Go 中支持最大的 M 的數(shù)量是 10000,但是操作系統(tǒng)中通常情況是不可以創(chuàng)建這么多的線程。
  • P:processor,可以理解成一個等待分發(fā)給 M 調(diào)度執(zhí)行的 goroutine 隊列。P的個數(shù)是由 runtime 的 GOMAXPROCS 來決定的。

M 和 P 存在一一對應(yīng)的綁定關(guān)系。大致的結(jié)構(gòu)圖如下所示:

圖片

goroutine 之旅

通常情況下,我們在代碼中執(zhí)行 go func(){}后,GMP 模型是如何工作的?通過一個詳細(xì)的圖來展示一下。

圖片

  1. 首先創(chuàng)建一個新的 goroutine
  2. 如果本地的局部隊列中有足夠的空間可以存放,則放入局部隊列中;如果局部隊列滿,則放入一個全局隊列(所有的 M 都可以從全局隊列中拉取 G 來執(zhí)行)
  3. 所有的 G 都必須在 M 上才可以被執(zhí)行,M 和 P 存在一一綁定的關(guān)系,如果 M 綁定的 P 中存在可以被執(zhí)行的 G,則從 P 中拉取 G 來執(zhí)行;如果 P 中為空,沒有可執(zhí)行的 G,則  M 從全局隊列中拉取;如果全局隊列也為空,則從其他的 P 中拉取 G
  4. 為 G 的運(yùn)行分配必要的資源,等待 CPU 的調(diào)度
  5. 分配到 CPU,執(zhí)行 func(){}

調(diào)度策略

整個 goroutine 調(diào)度器最重要的調(diào)度策略是:復(fù)用,避免頻繁的資源創(chuàng)建和銷毀,最大限度的提升系統(tǒng)的吞吐量和并發(fā)程度。這也是操作系統(tǒng)進(jìn)行線程調(diào)度的終極目標(biāo)。復(fù)用(reuse)也是很多「池化技術(shù)」的基礎(chǔ)。

圍繞著這一原則,goroutine 調(diào)度器在以下幾個方面進(jìn)行調(diào)度策略的優(yōu)化。

  1. 工作隊列的竊取機(jī)制:這個跟 Java 中的 ForkJoin Pool 的竊取機(jī)制同一原理,都是當(dāng)線程 M 空閑時,從其他繁忙的隊列 P 中"竊取"任務(wù) G 過來執(zhí)行,而不是銷毀空閑的 M。因為線程的創(chuàng)建和銷毀是需要消耗系統(tǒng)資源的,避免線程的頻繁創(chuàng)建和銷毀可以極大的提升系統(tǒng)的并發(fā)程度。
  2. 交接機(jī)制:當(dāng)線程M被阻塞的時候,M 會主動將 P 交接給其他空閑的 M。

另外,在 go 的 1.14 版本中,go 語言的技術(shù)團(tuán)隊嘗試在調(diào)度器中添加了可搶占的技術(shù)[https://github.com/golang/go/issues/24543]

  1. 搶占技術(shù)的出現(xiàn)一方面解決了線程 M 在執(zhí)行計算密集型任務(wù)時長時間占用 CPU,導(dǎo)致與之綁定的 P 上的其他 G 得不到執(zhí)行而造成的"饑餓現(xiàn)象";
  2. 另一方面,搶占技術(shù)的出現(xiàn)對 GC 來講解決 GC 時可能出現(xiàn)的 deadLock,相關(guān)的 issue 見:關(guān)于 GC 時 tight loops 應(yīng)該可以被搶占的討論
    [https://github.com/golang/go/issues/10958]
    。

最開始的 MG 模型

在 go 語言的早期,goroutine 調(diào)度器的模型并不是 GMP,而是 GM。整個調(diào)度器維護(hù)一個全局的 G 的等待隊列,所有的 M 從這個全局的隊列中拉取 G 來執(zhí)行,在 go1.1 中將這種模型直接干掉,取而代之的是現(xiàn)在的 GMP 模型,在 GM 模型的基礎(chǔ)上增加 P 局部隊列。官方之所有這么這么做,原因有二:

  1. 全局的 G 等待隊列,不同的M從隊列里取 G 都需要加鎖,鎖的粒度很大,嚴(yán)重制約了系統(tǒng)并發(fā)能力的提升;
  2. 沒有局部隊列,那么當(dāng)線程在執(zhí)行 IO 密集型操作時,M 阻塞在 IO 操作上,對應(yīng)的 G 也沒有辦法得到執(zhí)行(GMP 中可以將 G 交接給其他的 M 執(zhí)行),因此 GM 模型在應(yīng)對 IO 密集型任務(wù)時性能表現(xiàn)低下。
責(zé)任編輯:龐桂玉 來源: 字節(jié)跳動技術(shù)團(tuán)隊
相關(guān)推薦

2024-07-30 12:24:23

2024-09-02 09:00:59

2023-05-22 09:27:11

GMPGolang

2023-08-21 07:34:37

GolangGMP

2021-10-26 07:42:49

Go線程數(shù)GMP

2022-12-06 08:30:06

SchedulerReact

2025-05-26 00:05:00

2023-03-06 00:27:02

Kubernetesscheduler系統(tǒng)

2021-07-06 14:47:30

Go 開發(fā)技術(shù)

2024-02-19 07:40:10

2021-06-02 09:23:57

Go開發(fā)內(nèi)存

2024-06-27 07:56:49

2023-11-29 09:29:48

Kuberneteskube

2021-01-29 08:22:03

調(diào)度器Yarn架構(gòu)

2024-06-06 09:47:56

2023-08-10 08:01:36

RDB數(shù)據(jù)AOF

2023-03-26 23:47:32

Go內(nèi)存模型

2017-05-08 11:37:41

Go調(diào)度器源碼分析程序
點贊
收藏

51CTO技術(shù)棧公眾號