概览

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和 goroutine- g0,并把二者关联。
- 调度器初始化:初始化 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退出程序。