GO GMP模型简述

M:machine,代表一个内核线程,这个线程是操作系统来处理,操作系统辅助把它放置到一个core上去执行
P:processor,代表一个逻辑处理器,也就是执行代码的上下文环境
G:goroutine,代表一个并发的代码片段

P在M 上运行G

系统的线程调度发生在内核
GO中并发的基本单元Goroutine在用户空间,由G的调度器调度

线程代价
1、 内存空间:一般情况下一个thread的创建默认占用栈空间1M,Goroutine默认是2KB
2、 切换开销:thread的切换时需要通过用户态达到内核态,会涉及上下文的切换开销,对应资源的消费很大
3、 线程通信:线程通信由三种方法,使用起来比较复杂,最棘手的问题就是共享内存,一般会使用锁,会引申各种锁的问题,例如死锁
4、 资源回收:创建线程相对简单,回收线程资源会很麻烦,常见有detached和join两种方式,对于无法大量创建线程的时候,会考虑多路复用方式
在这里插入图片描述

两个线程M,每个都有自动的局部调度器,运行着一个G(蓝),同时还有三个排队等待运行的本地G(灰)

在这里插入图片描述

1、 Gobal队列:存放等待执行的G
2、 P的本地队列:当创建一个新的G之后优先加入本地队列,如果本地队列满了,会将G移到全局队列中,本地队列G数量不超过256个
3、 P列表:在初始化的时候根据GOMAXPROCS来设置
4、 M:线程想运行任务就要获取P,从P的本地队列获取G,P队列为空时,M也会尝试在全局队列拿一批G放到P队列中,或从其他P本地队列偷一半放到自己P本地队列,M运行G,G执行之后M会从P拿下个G继续执行

Goroutine调度器P和OS调度器时通过M结合起来,每一个M 代表一个内核线程,OS调度器负责把内核线程分配到CPU的核上执行

M0:时启动程序后编号为0 的主线程,这个M对应的实例会在全局变量runtime.m0中,不需要在heap上分配,M0负责执行初始化操作和启动第一个G之后就跟其他M一样

G0:每启动一个M都会创建一个Goroutine,G0仅仅负责调度G,G0不指向任何可执行的函数,每个M都会有自己一个G0。在调度或系统调用的时候会使用G0的栈空间,全局变量的G0是M0的G0

调度过程
1、 创建一个G对象,G对象保存到P本地队列或全局队列
2、 P去唤醒一个M。P继续执行它的执行序
3、 M寻找空闲的P,找到就将该G对象移动到它本身。接下来M执行一个调度循环(调用G对象执行清理线程继续找新的Goroutine执行)

M的只进行过程中,随时发生上下文切换。当上下文切换时,需要对执行现场进行保护,以便下次被调度执行时进行现场回复
Go调度器M的栈保存在G对象上,只需要将M所需要的寄存器(sp,pc等)保存到G对象上就可以实现现场保护。当这些寄存器数据保护起来,就可以随时执行上下文切换,在中断之前把现场保护起来。如果此时G任务还没执行完,M可以将任务重新丢到P的任务队列,等待下一次被调度执行。当再次被调度执行时,M通过访问G的vdsoSP,vdsoPC寄存器进行现场恢复(从上次终端位置继续执行)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值