Goroutine运行时间过长而发生的抢占调度详解~

原文地址:Goroutine运行时间过长而发生的抢占调度详解~

本文主要关注以下两点:

  1. 发生抢占调度的情况。

  2. 因运行时间过长发生的抢占调度的特点。

sysmon系统监控线程会定期(10毫秒)通过retake对goroutine发起抢占。

来看runtime/proc.go文件4376行分析retake:

// forcePreemptNS is the time slice given to a G before it is// preempted.const forcePreemptNS = 10 * 1000 * 1000 // 10msfunc retake(now int64) uint32 {
  
      n := 0    // Prevent allp slice changes. This lock will be completely    // uncontended unless we're already stopping the world.    lock(&allpLock)    // We can't use a range loop over allp because we may    // temporarily drop the allpLock. Hence, we need to re-fetch    // allp each time around the loop.    for i := 0; i < len(allp); i++ { //遍历所有的P        _p_ := allp[i]        if _p_ == nil {
  
              // This can happen if procresize has grown            // allp but not yet created new Ps.            continue        }               //_p_.sysmontick用于sysmon线程记录被监控p的系统调用时间和运行时间        pd := &_p_.sysmontick        s := _p_.status        if s == _Psyscall { //P处于系统调用之中,需要检查是否需要抢占            // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).            t := int64(_p_.syscalltick)            if int64(pd.syscalltick) != t {
  
                  pd.syscalltick = uint32(t)                pd.syscallwhen = now                continue            }            // On the one hand we don't want to retake Ps if there is no other work to do,            // but on the other hand we want to retake them eventually            // because they can prevent the sysmon thread from deep sleep.            if runqempty(_p_) &&  atomic.Load(&sched.nmspinning)+atomic.Load(&sched.npidle) > 0 && pd.syscallwhen+10*1000*1000 > now {
  
                  continue            }            // Drop allpLock so we can take sched.lock.            unlock(&allpLock)            // Need to decrement number of idle locked M's            // (pretending that one more is running) before the CAS.            // Otherwise the M from which we retake can exit the syscall,            // increment nmidle and report deadlock.            incidlelocked(-1)            if atomic.Cas(&_p_.status, s, _Pidle) {
  
                  if trace.enabled {
  
                      traceGoSysBlock(_p_)                    traceProcStop(_p_)                }                n++        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luyaran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值