天天看点

MPG线程模型简介

概述

go语言中的MPG线程模型对两级线程模型进行了一定程度的改进,使它能够更加灵活的进行线程之间的调度。

它由3个主要模块构成,如下图:

MPG线程模型简介

MPG的3个主要模块以及功能,我们通过下表所示。

模块 功能说明
Machine 一个Machine对应一个内核线程,相当于内核线程在go语言中的映射
Processor 一个Processor表示执行go代码片段的所必需的上下文环境,可以理解为用户代码逻辑的处理器
Goroutine 是对go语言中代码片段的封装,其实是一种轻量级的用户线程

为了更加形象,下面的介绍中我们会用M、P、G分别指代Machine、Processor和Goroutine。从图4-4可以看出,每一个

M都会与一个内核线程绑定,在运行时一个M同时只绑定一个P,而P和G的关系则是一对多。在运行过程中,M和内核线程之间

对应关系不会变化,在M的生命周期内,它只会与一个内核线程绑定,而M和P以及P和G之间的关系都是动态可变的。

在实际的运行过程中,M和P的组合才能够为G提供有效的运行环境,而多个可执行G将会顺序排成一个队列挂在某个P上面,

等待调度和执行,如图所示。

MPG线程模型简介

上图中,M和P共同构成了一个基本的运行环境,此时G0中的代码片段处于正在运行的状态,而右边的G队列处于待执行状态。

当没有足够的M来和P组合为G提供运行环境时,Go语言会创建新的M。在很多时候M的数量可能会比P要多。在单个go语言进程中,

P的最大数量决定了程序的并发规模,且P的最大数量是由程序决定的。可以通过修改环境变量GOMAXPROCS和调用函数runtime.GOMAXPROCS

来设定P的最大值。

M和P会适时的组合和断开,以保证待执行G队列能够得到及时运行。比如说图4-5中的G0此时因为网络I/O而阻塞了M,那么P就会携带剩余的

G投入到其他M中。这个新的M(M1)可能是新创建的,也可能是从调度器空闲M列表中获取的,这取决于此时的调度器空闲M列表中是否存在M,

这样的机制设计也是为了避免M过多创建。运行机制如图所示

MPG线程模型简介

当M对应的内核线程被唤醒时,M将会尝试为G0捕获一个P上下文,可能是从调度器的空闲P列表中获取,如果获取不成功,

M会把G0放入到调度器的可执行G队列中,等待其他P的查找。为了保证G的均衡执行,非空闲的P运行完自身的可执行G队列后,

会周期性从调度器的可执行G队列中获取待执行的G,甚至从其他的P的可执行G队列中掠夺G。

-------------------------------------------