donglan6967 2019-08-29 03:24
浏览 124

调用runtime.Gosched()与从通道接收之间用法上的区别?

I'm using an open source package that leverage the runtime.Gosched() to wait for a resource to be available. And found it may cause a high CPU usage. The code can be simplified to be like this:

func wait() {
    for {
        // check if something is available, and return it when available.
        // if size > oldSize {
        //  return buffer[oldSize:size-1]
        // }

        // In my case there's no write to the buffer for quite a long time
        // so that it keep arriving at this Gosched calling
        runtime.Gosched()
    }
}

func run() {
    for i := 0; i < 20; i++ {
        go wait()
    }
    time.Sleep(time.Second*20)
}

I have observed that it took all the CPU resource available when running the run() function. However, when using a channel, as the following code, there is no such problem.

func waitForChannel(ch chan struct{}) {
    <- ch
}

func runWithChannel() {
    ch := make(chan struct{})
    for i := 0; i < 20; i++ {
        go waitForChannel(ch)
    }
    time.Sleep(time.Second*20)
    //close(ch)
}

I know that I should use channels, when I want to wait for a resource and yield the current processor. However I can't find an explanation of the difference of waiting for a channel and calling Gosched over and over again. And what's the use case of Gosched, if it's not suitable for this situation.

  • 写回答

1条回答 默认 最新

  • dsn46282 2019-08-29 04:35
    关注

    The documentation for runtime.Gosched says:

    Gosched yields the processor, allowing other goroutines to run. It does not suspend the current goroutine, so execution resumes automatically.

    This suggests that what happens is that you may break out of the for loop of one Go routine but immediately enter the for loop of another Go routine. Thus the CPU is still busy running a lot of for loops, unable to take a breath.

    I will usually use a simple time.Sleep when waiting for another resource. Even the smallest duration will get the CPU usage of your example down to 0% (says the Task Manager):

    package main
    
    import "time"
    
    func wait() {
        for {
            time.Sleep(1)
        }
    }
    
    func main() {
        for i := 0; i < 20; i++ {
            go wait()
        }
        time.Sleep(time.Second * 20)
    }
    

    Note that you would usually say something like

    time.Sleep(time.Millisecond)
    

    or some other duration. I just wanted to illustrate that even the smallest timeout will give the CPU air to breathe.

    评论

报告相同问题?

悬赏问题

  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大
  • ¥15 import arcpy出现importing _arcgisscripting 找不到相关程序
  • ¥15 onvif+openssl,vs2022编译openssl64
  • ¥15 iOS 自定义输入法-第三方输入法