我已经找到了一种让代码按照我想要的方式运行的方法,但我想了解为什么它会这样运行,以便我对 Go 并发的理解有所提高。
我正在测试 sync.WaitGroup
以等待一些 goroutine 完成,因为我计划以这种方式向 Amazon S3 进行多次上传。
这是我最初的代码:
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go func() {
fmt.Println(i)
time.Sleep(time.Second * 1)
wg.Done()
}()
}
wg.Wait()
}
我惊讶地看到输出是:6, 6, 6, 6, 6
。
而不是像这样的:2, 4, 1, 5, 3
。
由于循环甚至没有转到 6,这对我来说毫无意义。
我后来将 i
变量作为参数传递给匿名函数
然后它的行为符合我的预期。
为什么会这样?我不明白。
最佳答案
这包含在常见问题解答中:What happens with closures running as goroutines?
在这种情况下,在 for 循环完成之前,不会调度任何 goroutine。为了 for 循环中断 i
不能小于或等于 5,因此此时它是 6。当 goroutines 运行时,它们各自打印在闭包中捕获的单个变量 i
的值。
当您将 i
作为参数传递给函数时,您将当前值复制到一个新变量,捕获当时的值。
关于使用 for 循环和匿名函数进行并发时出现意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37835492/