先看这个代码有问题吗?
文章目录
- 先看这个代码有问题吗?
- 问题
- 正确的是
- 如果不传递 i 给 goroutine,还会出现什么问题 ?
问题
-
在循环中启动了 goroutine (go func() {…}),但没有等待这些 goroutine 完成
-
主函数可能在所有 goroutine 执行前就结束了
-
循环变量 i 被所有 goroutine 共享,可能导致输出结果不符合预期
正确的是
package mainimport ("fmt""sync"
)func main() {testRange2()
}func testRange2() {arr := make([]int, 10)var wg sync.WaitGroupfor i := range arr {wg.Add(1)go func(val int) {defer wg.Done()fmt.Println(val)}(i) // 将 i 作为参数传递给 goroutine}wg.Wait() // 等待所有 goroutine 完成
}
如果不传递 i 给 goroutine,还会出现什么问题 ?
如果不将循环变量 i 作为参数传递给 goroutine,会出现一个常见且容易被忽视的问题:所有 goroutine 可能会打印出相同的值,通常是数组的最后一个索引值(在这个例子中是 9)。
这个问题的原因是:
-
闭包变量捕获机制:Go 中的闭包会捕获外部变量的引用,而不是值的副本。
-
循环变量共享:所有 goroutine 共享同一个循环变量 i 的引用。
-
执行时机:goroutine 的实际执行可能会延迟到循环结束后才开始。
循环结束时的变量状态:当循环结束时,i 的值已经变成了 10(超出了数组范围),或者在 range 循环的情况下是 9(最后一个索引)。