BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / golang / #2330同步于 2022/2/20
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Golang机器人发帖

go的协程调度问题

tiaoji
2022/2/20镜像同步8 回复
package main import ( "fmt" "runtime" "time" ) func main() { runtime.GOMAXPROCS(1) go func() { for { } }() time.Sleep(time.Millisecond) fmt.Println("finished.") } 这段代码在go1.13中运行是死循环,在go1.17中运行输出finished然后退出,为什么? 网上文章说“如果正在执行的G是个很耗时的操作且没有任何函数调用(如只是for循环中的计算操作),即使抢占flag已经被设置,该G还是将一直霸占着当前M直到执行完自己的任务。” 上面例子中死循环协程中并没有函数调用,为什么也发生了切换? https://github.com/k2huang/blogpost/blob/master/golang/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/%E5%B9%B6%E5%8F%91%E6%9C%BA%E5%88%B6/Go%E5%B9%B6%E5%8F%91%E6%9C%BA%E5%88%B6.md
订阅后,新回复会通过你的通知中心匿名送达。
8 条回复
sworduo机器人#1 · 2022/2/20
估计这个bug被修复了[ema21]
FAE机器人#2 · 2022/2/25
加入了基于信号的抢占式调度,就是内核向线程发的,然后劫持信号处理函数,把当前goroutine丢到全局队列去
Zelda机器人#3 · 2022/2/25
1.14的调度器改成preemptive的了。
lsj1342机器人#4 · 2022/2/25
1.13是协作式抢占,在存在函数调用时去判断是否抢占,for里面没有函数调用所以一直占着资源。 后面已经是基于信号的抢占式调度了
Jobszh机器人#5 · 2022/2/25
main函数退出整个进城都会退出
z217机器人#6 · 2022/2/25
https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-goroutine/#抢占式调度器 简单地来讲就是1.13之前是基于协作的抢占式调度,只有在发生函数调用时才进行抢占 1.14之后改成基于信号的抢占式调度,会在gc时触发抢占 【 在 tiaoji 的大作中提到: 】 : package main : import ( : ............
XinJiZheng机器人#7 · 2022/2/25
推荐B站幼麟实验室的抢占式调度详解,跟着源码的画图讲解 https://www.bilibili.com/video/BV1kL411p7mW?spm_id_from=444.41.0.0
tiaoji机器人#8 · 2022/2/28
我自己弄明白了。 go的调度有以下几种方式: 1.主动调度 自己主动放弃执行,通过runtime.Gosched()实现。取消G与M之间的绑定关系,将G放入到全局运行对列中去。 2.被动调度 这个主要发生在sleep,channal堵塞,垃圾回收等情况。通过调用gopark函数完成别动调度,该函数会解除G与M之间的关系,根据被动调度的原因不同,执行不同的waitunlockf函数,并开始新一轮的执行。 3.抢占调度 主要抢占执行时间过长的G和出于系统调用阶段的G。 抢占调度依赖一个监控线程,该线程在独立的M上运行,不需要绑定逻辑处理器P。 1)抢占执行时间过长的G,发生在函数调用的时候。代码编译的时候,编译器会在函数调用前加入一些检测代码。当该G执行时间超过10ms时,监控线程会对这段检测代码中的某些标志位做设置,当发生函数调用时,检测到这些设置,发生重新调度。 2)抢占系统调用。当G在系统调用中超过10ms时,且任务比较繁忙时,将发生抢占调度(任务不忙时,抢占没有意义,任务繁忙的判断有一些具体的标准,该处省略)。抢占原理时将P让出。该P让出后,可以与其他M绑定执行别的任务。 在1.13版本及之前大概就这么多。1.14开始有变化。 主要变化发生在 3.抢占调度 中存在问题。当cpu密集型任务执行时,可能没有发生函数调用,也没有系统调用,这样就没法进行抢占。 优化的目的就是要想办法打断G的执行,然后执行调度。这里采取的时通过信号来进行中断的方式。 监控线程检测到某个G执行时间过长,就发送信号_SIGURG,然后程序在处理信号时,修改了原程序中某些寄存器的值,使得程序继续执行的方向发生了改变。也就是当信号中断处理结束后,程序恢复运行的时候,不会再继续执行了,而是去执行新一轮的调度函数。