关于goroutine调度器是否是抢占式的问题

       最近在看协程的实现,想弄明白go的调度器是不是抢占式,如果某个goroutine运行的时间太久,并且没有主动让出cpu,go调度器是否会切换到其他goroutine运行。

看了一些其他的文章,总结了一下,go的调度器勉强算的上是抢占式的,但是不是在所有情况下都能抢占。按照go调度器的设计,最终还是让长时间运行的goroutine自己放弃cpu的,以主动放弃达到抢占的目的。go调度器会起一个守护线程去监控各个协程的运行时间,一旦某个协程运行超时,就给这个协程的栈空间设置一个超时的标志位,协程在运行的过程中经常检查这个标志位,检测自己是否运行时间超时。一旦检测到超时,就主动调用yield将cpu的执行权交给调度器,让调度器选择下一个goroutine执行。

       那关键是协程在什么时机检查这个超时标志位呢?那就是goroutine每次在执行非内联函数的时候。因此如果goroutine空循环,或者没有执行非内联函数,那么还是无法被抢占的。会永远运行下去,调度器也无能为力。

      go调度器对计算密集型的任务,的是不是真的跟以上说法一致?

 

下面的代码,编译好后运行在只有单cpu的机子上运行(必须是单核的,如果是多核,go调度器会把两个协程分别运行在多个线程上,让我们无法分别是否切换了协程执行),可以在虚拟机上运行,虚拟机方便更改cpu核数

package main
import (
    "fmt"
)   
func thread(i int){
    for {
        if 0 == i {
        fmt.Printf("long printf ================================%v\n",i)
        } else {    
        fmt.Printf("short printf%v\n",i)
        }
        
    }   
}   
func main(){
    for i := 0; i < 2; i++ {
        go thread(i)
    }   
    //runtime.Gosched()
    fmt.Scanln()
}   

以上测试结果,long printf和short printf 都会打印出来,只是需要观察久一点,大概几分钟,从我自己测试的结果看,协程切换的不频繁。说明在只使用printf函数的情况下,协程还是会得到切换的,我们不清楚是不是printf函数内部是不是有出让cup的动作,或者什么其他机制检测运行超时,但是的确是有协程的切换的

参考文章:

两种任务调度方式(goroutine,coroutine)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值