英文:
Loop in goroutine hangs program
问题
为什么当注释掉time.Sleep(time.Nanosecond)
时,以下程序会卡住?
package main
import "fmt"
import "time"
import "sync/atomic"
func main() {
var ops uint64 = 0
for i := 0; i < 50; i++ {
go func() {
for {
atomic.AddUint64(&ops, 1)
time.Sleep(time.Nanosecond)
}
}()
}
time.Sleep(time.Millisecond)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
第二个问题,为什么在沙盒中运行这个程序会导致"process took too long"的错误?
英文:
Why does the following program hang when the time.Sleep(time.Nanosecond)
is commented out?
package main
import "fmt"
import "time"
import "sync/atomic"
func main() {
var ops uint64 = 0
for i := 0; i < 50; i++ {
go func() {
for {
atomic.AddUint64(&ops, 1)
time.Sleep(time.Nanosecond)
}
}()
}
time.Sleep(time.Millisecond)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
Second question, why does running this program in the sandbox result in "process took too long"?
答案1
得分: 10
这是要翻译的内容:
这是因为goroutine是协作式(而非完全抢占式)任务,只有在发生IO、系统调用、time.Sleep()
或调用需要扩展栈的大型函数时才会发生上下文切换。
参考资料:
你的atomic.AddUint64(&ops, 1)
是一个不需要扩展栈的小函数,因此不会发生上下文切换。
由于主线程也是一个goroutine,它不会进行上下文切换,并且永远处于睡眠状态。
有一个未解决的问题,即在紧密循环中使golang具有抢占性。
更多有用的参考资料:
英文:
It's because goroutine is cooperative (not fully preemptive) task, and the context switch only happen when there's some IO, system call, time.Sleep()
, or calling large function which have to extend the stack.
Reference:
Your atomic.AddUint64(&ops, 1)
is small function which does not have to extend stack. so the context switch never occurs.
Since main thread is also a goroutine, it does not acquire context switch, and sleeps forever.
There's an open issue to make golang preemptive in tight loop, but not yet solved.
More useful references:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论