采用这段代码:
package main
import (
"fmt"
"time"
)
func main() {
var x int
go func() {
for {
x++
}
}()
time.Sleep(time.Second)
fmt.Println("x =", x)
}
为什么x
最后等于0
?我知道Go的调度程序需要time.Sleep()
调用才能提取goroutine,但为什么不这样做呢?
Hint:在for循环中放置time.Sleep()
或对runtime.Gosched()
的调用可修复此代码。但是为什么呢?
更新:检查以下版本的相同代码:
package main
import (
"fmt"
"time"
)
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。编译器在此进行任何优化吗?
这是一个通用的多处理问题,不只适用于goroutine或Go。
无法保证代码中语句的执行顺序。例如,以下顺序是可能的(假设“ G”是您的goroutine,而“ M”是main
中的代码):
x
G
定义并调用Sleep
被叫Sleep
完成Println
(x = 0
)x++
x++
观察一些交错尝试:
package main
import (
"fmt"
"time"
)
func main() {
var x int
go func() {
for {
time.Sleep(time.Second)
x++
}
}()
time.Sleep(5*time.Second)
fmt.Println("x =", x)
}
但是,仍然没有保证。要获得任何保证,请使用任何同步技术,例如频道。