Go GPM的理解 與 runtime包

LiberHome發表於2022-05-07

理解GPM

Go語言的scheduler的實現原理

Go語言中支撐整個scheduler實現的主要有四個結構,分別是G、P、M、Sched,前三個定義在runrtime.h,Sched定義在proc.c中。

  • Sched結構就是排程器,維護了儲存M和G的佇列,以及排程器的一切狀態資訊
  • G是goroutine實現的核心結構,是對一個要併發執行的任務的封裝,可以稱作為使用者態的執行緒,屬於使用者級資源,對作業系統透明,輕量級,可以大量建立,上下文的切換成本低。
  • P是Processor,邏輯處理器,主要作用是管理G物件,併為G在M上的執行提供本地化資源,他維護了一個goroutine佇列runqueue,也可以理解為goroutine的上下文環境。
  • M是Machine,是利用系統呼叫建立出來的作業系統執行緒實體,作用是執行G中的併發任務,代表了一個核心執行緒,由作業系統管理,goroutine就是執行在M上的,M中維護了小物件記憶體mcache,當前執行的goroutine,隨機數發生器等資訊。

runtime包

runtime類似於Java或者.Net中的虛擬機器,負責記憶體分配,垃圾回收,goroutine,chanel,切片,map,反射等等。

runtime包的常用函式

package main

import (
    "fmt"
    "runtime"
)

func main() {
    //獲取goroot目錄
    fmt.Println("GOROOT: ", runtime.GOROOT())
    //獲取作業系統
    fmt.Println("os/platform: ", runtime.GOOS)
    //獲取當前邏輯cpu的數量,當然也可以用runtime.GOMAXPROCS()手動設定邏輯CPU的數量,不過GO1.8之後不用設定,預設執行在多核
    fmt.Println("邏輯cpu的數量: ", runtime.NumCPU())
    //GOsched: 讓當前的額goroutine讓出當前的時間片,當一個goroutine發生阻塞的時候,go會把所有和這個阻塞goroutine處於
    //同一個系統執行緒中的其他goroutine移植到其他系統執行緒上從而使之不被阻塞。
    go func() {
        for i := 0; i < 3; i++ {
            fmt.Println("goproutine")
        }
    }()
    for i := 0; i < 3; i++ {
        //讓出時間片,讓其他goroutine先執行
        runtime.Gosched()
        fmt.Println("...........................main")
    }
}
package main

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

func main() {

    go func() {
        fmt.Println("goroutine開始")
        //呼叫fun
        fun()
        fmt.Println("goroutine結束")
    }()
    //為了主程式不結束 我們讓他睡一會
    time.Sleep(3 * time.Second)
}

func fun() {
    defer fmt.Println("defer job")
    runtime.Goexit() //終止當前的goroutine
    fmt.Println("fun函式")
}

其他還有很多,用到的時候可以檢視官方文件:https://golang.google.cn/pkg/

參考資料:bilibili

相關文章