概览
GPM 分别代表
- G: Goroutine, Go协程,是参与调度与执行的最小单元。
- P: P, Processor,指的是逻辑处理器,P关联了本地可运行的G队列,最多可存放256个G。P的数量最多是
GOMAXPROCS
(可配置)个。 - M: M, Machine,指的是系统级线程,Go程序启动时会设置M的最大数量,默认为10000,但是内核很难支持这么多的线程,所以这个限制可以hulue。
调度器的生命周期
m0
M0
是启动程序后的编号为0的主线程,这个M
对应的实例会在全局变量runtime.m0中,不需要在Heap上分配,M0负责执行初始化操作和启动第一个G
,在之后M0就和其他的 M
一样了。
G0
G0
是每次启动一个 M
都会第一个创建的 goroutine,G0
仅用于负责调度的 G
,G0
不指向任何可执行的函数,每个M
都会有一个自己的G0
,在调度或者系统调用时会使用G0
的栈空间,全局变量的G0
是M0
的G0
。
|
|
以上代码所示,分析一下执行过程
runtime
创建最初的线程m0
和 goroutineg0
,并把二者关联。- 调度器初始化:初始化 m0、栈、垃圾回收,以及创建和初始化由
GOMAXPROCS
个P
构成的P
列表。 - 示例代码中的 main 函数是
main.main
,runtime
中也有一个main函数 -runtime.main
,代码经过编译后,runtime.main
会调用main.main
,程序启动时会为runtime.main
创建goroutine
,称它为main goroutine
。然后把main goroutine
加入到P
的本地队列中。 - 启动
m0
,m0
已经绑定了P
,会从P
的本地队列获取G
,然后获取到main goroutine
。 G
拥有栈,M
根据G
中的栈信息和调度信息设置运行环境。M
运行G
。G
退出,再次回到M
获取可运行的G
,这样重复下去,直到main.main
退出,runtime.main
执行 Defer 和 Panic 处理,或调用runtime.exit
退出程序。