英文:
Does using `runtime.Gosched()` in the default case of a Select statement make any sense?
问题
根据Go的文档,Gosched函数会让出处理器,允许其他goroutine运行。它不会挂起当前的goroutine,所以执行会自动恢复。
根据这个定义,如果我有一系列长时间运行的goroutine被创建并发执行,将下面的select语句写成这样是否有优势:
for {
select {
case msg := <-msgch :
fmt.Println(msg)
default:
runtime.Gosched()
}
}
根据文档,我认为这段代码可以导致更多的goroutine运行。我的假设正确吗?
英文:
Go's documentation says that
> Gosched yields the processor, allowing other goroutines to run. It does not suspend the current goroutine, so execution resumes automatically.
Based on that definition if I have a series of long running go routines being created and executed concurrently, would it be advantageous to write a select statement the following way:
for {
select {
case msg := <- msgch :
fmt.Println(msg)
default:
runtime.Gosched()
}
}
I assume based on the documentation, this code can result in more go routines being run. Is my assumption correct?
答案1
得分: 4
不,这里不需要使用runtime.Gosched
,因为在Go中,当goroutine在等待通道或等待I/O时,它会自动让其他goroutine运行。这个特性从Go 1.0版本就存在了。
在Go 1.2中,Go运行时调度器在调用函数时添加了自动抢占点。在此之前,如果你有一个CPU密集型的循环(即使有函数调用),它可能会饿死调度器,你可能需要使用runtime.Gosched
。
然后在Go 1.14中,他们进一步改进了运行时的这个方面,即使是没有函数调用的紧密CPU密集型循环也会被自动抢占。
因此,在任何Go版本中,当你只是在等待通道或I/O时,不需要调用runtime.Gosched
;在1.14之前,如果你进行长时间的计算,可能需要调用它。但是在Go 1.14+中,我不认为你需要手动调用它。
如果我正在审查你的实际代码,我建议将其改为简单的for ... range
循环:
for msg := range msgCh {
fmt.Println(msg)
}
这将等待每个消息的到来并打印它,如果通道关闭,则停止。然而,如果你正在等待另一个通道或完成信号(例如上下文),你可能需要使用switch
。类似这样:
for {
select {
case msg := <-msgCh:
fmt.Println(msg)
case <-ctx.Done():
return
}
}
英文:
No, it isn't necessary here, because whenever Go is waiting on a channel or waiting for I/O, it allows other goroutines to run automatically. That's been the case since Go 1.0.
In Go 1.2 the Go runtime's scheduler added automatic preemption points whenever you called a function. Prior to that if you had a CPU-bound loop (even with a function call) it could starve the scheduler and you might need runtime.Gosched
.
And then in Go 1.14, they made this aspect of the runtime even better, and even tight CPU-bound loops with no functions calls are automatically pre-empted.
So with any Go version, you don't need to call runtime.Gosched
when you're just waiting on a channel or on I/O; before 1.14, you may have wanted to call it if you were doing a long-running calculation. But with Go 1.14+, I don't see why you'd ever need to call it manually.
If I was reviewing your actual code, I'd suggest changing it to a simple for ... range
loop:
for msg := range msgCh {
fmt.Println(msg)
}
This will wait for each message to come in and print it, and stop if/when the channel is closed. However, you would want a switch
if you're waiting on another channel or done signal, for example a context. Something like this:
for {
select {
case msg := <- msgCh:
fmt.Println(msg)
case <-ctx.Done():
return
}
}
答案2
得分: 1
使用runtime.Gosched()
是否有任何意义?
不。基本上不需要或没有意义使用Gosched。
英文:
> Does using runtime.Gosched()
[anywhere] make any sense?
No. It basically is never needed or sensible to use Gosched.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论