Go runtime 调度器精讲:异步抢占
原创文章,欢迎转载,转载请注明出处,谢谢。
前面介绍了运行时间过长和系统调用引起的抢占,它们都属于协作式抢占。本讲会介绍基于信号的真抢占式调度。
在介绍真抢占式调度之前看下 Go 的两种抢占式调度器:
抢占式调度器 - Go 1.2 至今
-
基于协作的抢占式调度器 - Go 1.2 - Go 1.13
改进:通过编译器在函数调用时插入 抢占检查 指令,在函数调用时检查当前 Goroutine 是否发起了抢占请求,实现基于协作的抢占式调度。
缺陷:Goroutine 可能会因为垃圾收集和循环长时间占用资源导致程序暂停。 -
基于信号的抢占式调度器 - Go 1.14 至今
改进:实现了基于信号的 真抢占式调度 。
缺陷 1:垃圾收集在扫描栈时会触发抢占式调度。
缺陷 2:抢占的时间点不够多,不能覆盖所有边缘情况。
( 注:该段文字来源于 抢占式调度器 )
协作式抢占是通过在函数调用时插入 抢占检查 来实现抢占的,这种抢占的问题在于,如果 goroutine 中没有函数调用,那就没有办法插入 抢占检查 ,导致无法抢占。我们看 Go runtime 调度器精讲(七):案例分析 的示例:
//go:nosplit
func gpm() {
var x int
for {
x++
}
}
func main() {
var x int
threads := runtime.GOMAXPROCS(0)
for i := 0; i < threads; i++ {
go gpm()
}
time.Sleep(1 * time.Second)
fmt.Println("x = ", x)
}
禁用异步抢占:
# GODEBUG=asyncpreemptoff=1 go run main.go
程序会卡死。这是因为在 gpm 前插入
//go:nosplit
会禁止函数栈扩张,协作式抢占不能在函数栈调用前插入
抢占检查
,导致这个 goroutine 没办法被抢占。
而基于信号的真抢占式调度可以改善这个问题。
以上就是电脑114游戏给大家带来的关于Go runtime 调度器精讲:异步抢占全部内容,更多攻略请关注电脑114游戏。
电脑114游戏-好玩游戏攻略集合版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!