理解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