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

ove*_*nge 0 concurrency loops go goroutine

在下面的代码中:

package main

import "fmt"

func main() {
    for i := 0; i <= 9; i++ {
        go func() {
            fmt.Println(i)
        }()
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

code$ 
code$ go install github.com/myhub/cs61a
code$ bin/cs61a 
code$ 
Run Code Online (Sandbox Code Playgroud)

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

1)他们是否i在 10 个 go-routines 之间进行单一内存位置的数据竞争?

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

icz*_*cza 7

有数据竞赛吗?

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

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

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

使固定

复制循环变量,并在闭包中使用它,并使用 async.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()
Run Code Online (Sandbox Code Playgroud)

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

9
0
2
1
6
5
3
7
8
4
Run Code Online (Sandbox Code Playgroud)

另一种方法是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()
Run Code Online (Sandbox Code Playgroud)

Go Playground上试试这个。