调用运行时之间的用法差异.Gosched() 并从通道接收?



我正在使用一个开源包,它利用runtime.Gosched()来等待资源可用。并发现可能会导致CPU使用率过高。代码可以简化为如下所示:

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)
}

我观察到在运行 run(( 函数时它占用了所有可用的 CPU 资源。但是,在使用通道时,如以下代码所示,不存在此类问题。

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)
}

我知道当我想等待资源并产生当前处理器时,我应该使用通道。但是,我找不到等待频道和一遍又一遍地打电话给Gosched的区别的解释。Gosched的用例是什么,如果它不适合这种情况。

运行时的文档。戈舍德 说:

Gosched 产生处理器,允许其他 goroutines 运行。它不会挂起当前的 goroutine,因此执行会自动恢复。

这表明发生的情况是,您可能会突破一个 Go 例程的for循环,但立即进入另一个 Go 例程的for循环。因此,CPU仍然忙于运行大量for循环,无法喘口气。

在等待另一个资源时,我通常会使用一个简单的time.Sleep。即使是最短的持续时间也会使示例的 CPU 使用率降至 0%(任务管理器说(:

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)
}

请注意,您通常会说类似

time.Sleep(time.Millisecond)

或其他一些持续时间。我只是想说明,即使是最小的超时也会让 CPU 呼吸。

运行时。Gosched 函数生成处理器,以便其他 goroutines 可以运行。它不会挂起调用 goroutine。

但是,我找不到等待频道和一遍又一遍地打电话给Gosched的区别的解释。

通道上的接收会暂停接收 goroutine,直到值可用或通道关闭。

对 Gosched 的调用会生成处理器,以便其他 goroutines 可以运行,但它不会挂起 goroutine。go例程中的循环继续旋转并消耗 CPU 资源。

Gosched的用例是什么,如果它不适合这种情况。

很少有程序需要调用Gosched。

通道发送和接收、互斥锁和解锁、I/O等操作都可以产生处理器。这些屈服点通常足以满足应用需求。

在长时间运行的操作中需要 Gosched 调用,否则不会生成处理器。例如,不执行任何 I/O 的长时间运行的数值计算。

相关内容

  • 没有找到相关文章