runqget 中返回的 inheritTime 具体有什么作用呢?

来源:1-4 Go 程序是怎么跑起来的

xiaobaixiao

2021-05-17 17:34:07

runqget 会返回一个 inheritTime 值,看源码知道这个值跟 p.schedtick 有关,但是还是不理解为什么 runqget需要返回这个值。跟时间片又有什么关系呢?

// If inheritTime is true, gp inherits the remaining time in the
// current time slice. Otherwise, it starts a new time slice.
// Never returns.
func runqget(_p_ *p) (gp *g, inheritTime bool) {
	// If there's a runnext, it's the next G to run.
	for {
		next := _p_.runnext
		if next == 0 {
			break
		}
		if _p_.runnext.cas(next, 0) {
			return next.ptr(), true
		}
	}

	for {
		h := atomic.LoadAcq(&_p_.runqhead) // load-acquire, synchronize with other consumers
		t := _p_.runqtail
		if t == h {
			return nil, false
		}
		gp := _p_.runq[h%uint32(len(_p_.runq))].ptr()
		if atomic.CasRel(&_p_.runqhead, h, h+1) { // cas-release, commits consume
			return gp, false
		}
	}
}

写回答

1回答

昵称咋还不能重复呢

2021-05-17

结论: runnext与主协程共享时间片, 防止两者相互阻塞-唤醒导致其他协程饥饿.


我看了下源码,  如果调度的时候, 获取了runnext, 而不是其他队列的g,  那就继承时间片, 其他情况基本都是不继承.

http://img.mukewang.com/climg/60a26fe30957999e09180546.jpg

在接下来的execute方法中, 可以看到. 如果不继承, 就schedtick++, 继承的话就不变. 

http://img.mukewang.com/climg/60a26fc709779fc606440380.jpg

这样的话, sysmon里根据schedtick来计算协程有没有运行太久.  如果schedtick变了, 那表示开启新的一轮计算. 没变的话, 表示复用一个时间片. 

http://img.mukewang.com/climg/60a2707109adb1ef06760755.jpg

这样看起来像可以防止一个协程不停的启动/等待子协程, 然后子协程运行, 又复活父协程. (没有父子关系, 大概这个意思).


所以我去翻了下这个commit, 还比较难翻到. 基本我就是我说的这个意思. 

https://go-review.googlesource.com/c/go/+/9289/

runtime: yield time slice to most recently readied G



这个是和runnext一起优化.

  1. runnext可以加快上面说的运行模型

  2. 共享时间窗口, 又能避免因为不停的ping-pong双向唤醒导致其他协程饥饿


快来给我点赞吧. 

by 助教听闻


13
hiaobaixiao
hp style="white-space:normal;">懂了,原来 runnext 是跟 inheritTime 是在一个 commit 中,有了这个背景就好理解多了。

谢谢听闻助教。?


h021-05-18
共1条回复

Go高级工程师实战营

慕课网与 GoCN 社区官方联手打造,定义行业Go高级人才培养标准,4个月,快速晋升为P6+/D7级高级人才。

458 学习 · 266 问题

查看课程