Go vet - 由 func 文字捕获的循环变量



在下面的代码中:

package main
import "fmt"
func main() {
for i := 0; i <= 9; i++ {
go func() {
fmt.Println(i)
}()
}
}

输出:

code$ 
code$ go install github.com/myhub/cs61a
code$ bin/cs61a 
code$ 

上述程序不提供任何输出。

1) 他们是 10 个 go-routines 中单个内存位置i的数据竞赛吗?

2)为什么上面的代码不打印自由变量i的值?

有数据竞赛吗?

是的,通过运行go run -race example.go进行确认。主 goroutine 写入i,其他 goroutine 在没有任何同步的情况下读取它。请参阅将参数传递给函数闭包;为什么这两个循环变体会给我不同的行为?并使用循环切片/地图的范围注册多个路线。

为什么上面的代码不打印任何东西?

因为当主程序结束时,您的程序也会结束。它不会等待其他非maingoroutines 完成。请参阅goroutine没有输出

修复

复制循环变量,并在闭包中使用它,并使用sync.WaitGroup等待启动的goroutines结束:

var wg sync.WaitGroup
for i := 0; i <= 9; i++ {
i2 := i
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println(i2)
}()
}
wg.Wait()

这将输出(在Go Playground上尝试):

9
0
2
1
6
5
3
7
8
4

另一种方法是将i作为参数传递给启动的函数:

var wg sync.WaitGroup
for i := 0; i <= 9; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println(i)
}(i)
}
wg.Wait()

在Go Playground上试试这个。

最新更新