使用 for 循环和匿名函数进行并发时出现意外行为

标签 go

我已经找到了一种让代码按照我想要的方式运行的方法,但我想了解为什么它会这样运行,以便我对 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/

相关文章:

pointers - 存储为值的接口(interface);无法更新结构字段的方法

Golang return map[string]interface{} 返回变量结构

pointers - slice 指针的内存值是什么意思?

go - 如何将 go get 与私有(private) github 企业服务器一起使用?

go - 使用/rs/cors 作为 Buffalo 的预制件的示例?

parsing - 如何实现BNF语法树来解析GO中的输入?

json - 在 Go 中从 POST 请求解码 JSON 失败

string - 调用带有特殊前缀/后缀的函数

go - 比较文本文件的列

go - 如何调用在根包上声明的变量