go的调度机制

摸清go的调度机制之前,先来说说线程模型,一般分为三种,取决于用户级线程和内核级线程的对应关系。

第一种:N:1,多个用户态的线程对应着一个内核线程,这种模型上下文切换成本低,但不能利用多核。

第二种:1:1,一个用户态线程对应一个内核线程,这种模型可以利用多核,但上下文切换成本高。

第三种:M:N,M个用户线程对应N个内核线程,结合上面两种模型的优点,既能利用多核资源也能尽可能减少上下文切换成本,但是调度算法的实现成本偏高。

Go语言的线程模型就是这一种特殊的线程模型,也就是GPM调度模型

GPM各代表什么呢?

G: G代表的是一个goroutine对象,常说的协程,真正携带代码执行逻辑的部分。

M:M代表的是一个内核级线程,所有的G任务,最终还是在M上执行。

P:P代表的是一个处理器,P是用一个全局数组(255)来保存的,并且维护着一个全局的P空闲链表,一个P可以对应多个M,但同一时刻只能与一个M绑定关系,

M 被创建之后需要自行在 P 的空闲链表中找到 P 进行绑定,没有绑定 P 的 M,会进入阻塞态;P的数量由GOMAXPROCS来配置,最大为256,默认值为CPU核心数。

每一个P保存着本地G任务队列,也有一个全局G任务队列;

go调度的过程:

1.创建一个G对象,加入到本地队列或者全局队列

2.如果有一个空闲的p,就创建一个M,没有就返回

3.创建M时,底层会创建一个内核线程,循环执行能找到的G任务

4.G任务的执行顺序是,先在本地队列查找,再到全局队列(一次性转移(全局G个数/P个数)个,最后到其他P查找(一次性转移一半)

5. 以上的G任务执行是按照队列顺序(也就是go调用的顺序)执行的

如果G任务执行太长,就会一直占用着这个线程,由于本地队列的G任务是顺序执行的,其它G任务就会阻塞了,怎样中止长任务的呢?

启动的时候会创建一个线程sysmon,用来监控和管理,在内部是一个循环:

1.记录所有P的G任务计数schedtick,schedtick会在每执行一个G任务后递增

2.如果schedtick一直没有增长,说明这个P一直执行同一个G任务,如果超过一定时间(10ms),这个G任务的栈信息会添加一个标记

3.如果G任务在执行的时候,遇到非内联函数,就会检查这个标记,中断自己,把自己放到队列末尾,执行下一个G任务

4.中断的时候会把寄存器的栈信息保存到自己G对象里面

5.当再次执行的时候,将自己保存的栈信息复制到寄存器里面

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值