goroutine 调度器 GPM #
- 全局队列(Global Queue):存放等待运行的G。
- P的本地队列:同全局队列类似,存放的也是等待运行的G,存的数量有限,不超过256个。新建G’时,G’优先加入到P的本地队列,如果队列满了,则会把本地队列中一半的G移动到全局队列。
- P列表:所有的P都在程序启动时创建,并保存在数组中,最多有
runtime.GOMAXPROCS
个。 - M:线程想运行任务就得获取P,从P的本地队列获取G,P队列为空时,M也会尝试从全局队列拿一批G放到P的本地队列,或从其他P的本地队列偷一半放到自己P的本地队列。M运行G,G执行之后,M会从P获取下一个G,不断重复下去。
Goroutine调度器和OS调度器是通过M结合起来的,每个M都代表了1个内核线程,OS调度器负责把内核线程分配到CPU的核上执行。
P(Processor) 的数量由 GOMAXPROCS
来决定。也就是说同一时间内仅能有 GOMAXPROCS
个 goroutine 在并行运行。
M(Thread) 的数量默认为 10000(OS 一般无法支撑这么多的线程数) ,通过 runtime/debug
的 SetMaxThread
可以设置 M 的数量。
当 P 需要 M ,但所有的 M 都阻塞了,P 就会创建出新的 M 来执行任务。
因此一般来说,会将 runtime.GOMAXPROCS
设置为机器 CPU 核数,那么就会有 CPU 核数个 P(Processor) 。而 M 和 G 都是不定的。