【发布时间】:2020-04-03 17:21:40
【问题描述】:
获取这段代码:
func main() {
var x int
go func() {
for {
x++
}
}()
time.Sleep(time.Second)
fmt.Println("x =", x)
}
为什么x最后等于0?我知道 Go 的调度程序需要 time.Sleep() 调用来获取 goroutine,但为什么它不这样做呢?
提示: 将time.Sleep() 或对runtime.Gosched() 的调用放入for 循环可修复此代码。但为什么呢?
更新:检查相同代码的以下版本:
func main() {
var x int
go func() {
for i := 0; i < 10000; i++ {
x++
}
}()
time.Sleep(time.Second)
fmt.Println("x =", x)
}
奇怪的是,goroutine 中的代码现在被执行了,x 不再是 0。编译器在这里做了任何优化吗?
【问题讨论】:
-
您的代码存在竞争条件(变量
x的并发读写),因此行为未定义。 -
@Adrian 但我在等待阅读
x。您甚至可以确定增加睡眠时间。我的问题的重点是为什么x是0? -
没关系 - 你的 goroutine 运行一个无限循环,所以无论你等待多长时间读取它,仍然存在并发写入。你的问题的答案是“你有一个竞争条件,所以行为是未定义的”。
-
@HamedMomeni 我相信对于“未定义”的含义有些混淆。这意味着 anything 是该程序的有效输出。未定义的行为并不意味着“一小组预期结果,我们可以以一定的概率猜测哪些结果”。这个程序是未定义的,所以它可以做任何事情;打印任何东西,不打印任何东西,删除文件,无法终止。 Anything 将被视为编译器的正确输出。探索 Go 编译器是如何实现的,这不是一个坏问题,但 undefined 是 undefined。
-
@RobNapier 是的,你是对的,我为我的错误道歉。这里我只是想了解编译器或调度器在这种特定情况下是如何工作的。
标签: go goroutine go-scheduler