使用for循环和匿名函数执行并发性的行为意外 [英] Go concurrency with for loop and anonymous function behaves unexpectedly

查看:138
本文介绍了使用for循环和匿名函数执行并发性的行为意外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经找到了代码行为的一种方法,但我想知道为什么它的行为如此,以至于我对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 变量作为参数
传递给匿名函数,然后按照我的预期行事。



为什么会发生这种情况?我不理解它。 解决方案

常见问题解答:以goroutine的形式运行的闭包会发生什么情况?



在这种情况下,没有一个goroutines会被安排到for循环完成。为了使for循环中断 i 不能小于或等于5,因此在那个点上是6。当goroutines运行时,它们每个都打印在闭包中捕获的单变量 i 的值。

当您将 i 作为参数传递给函数时,将当前值复制到一个新变量中,捕获当时的价值。

I have already found out a way for the code to behave as I want, but I would like to understand why it behaves like this so that my understanding of Go concurrency improves.

I was testing out sync.WaitGroup to wait for some goroutines to finish because I plan on doing multiple uploads to Amazon S3 in this way.

This was the code I had originally:

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()
}

I was surprised to see that the output was: 6, 6, 6, 6, 6.

Instead of something like: 2, 4, 1, 5, 3.

Since the loop does not even go to 6, this made no sense to me. I later passed the i variable to the anonymous function as argument and then it behaved as I expected.

Why does this happen? I don't understand it.

解决方案

This is covered in the faq: What happens with closures running as goroutines?

In this case, none of the goroutines get scheduled until the for loop completes. In order for the for loop to break i must not be less than or equal to 5, therefore it is 6 at that point. When the goroutines run, they each print the value of the single variable i which is captured in the closures.

When you pass i as an argument to the function, you copy the current value to a new variable, capturing the value at that moment.

这篇关于使用for循环和匿名函数执行并发性的行为意外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆