与 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变量作为参数传递给匿名函数,然后它的行为符合我的预期。


为什么会发生这种情况?我不明白。


料青山看我应如是
浏览 144回答 2
2回答

拉丁的传说

在这种情况下,在 for 循环完成之前,不会调度任何 goroutine。为了使 for 循环中断,i必须不小于或等于 5,因此在该点为 6。当 goroutine 运行时,它们每个都会打印i在闭包中捕获的单个变量的值。当您将i参数作为参数传递给函数时,您将当前值复制到一个新变量中,并捕获当时的值。

慕侠2389804

要回答您的问题,您必须传入i您的,func以便每个例程都有自己的i.所以你的代码应该是这样的func main() {&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; for i := 1; i <= 5; i++ {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func(i int) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(time.Second * 1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; }(i)&nbsp; &nbsp; }&nbsp; &nbsp; wg.Wait()}我编写了这个实用程序函数来帮助并行化一组函数:import "sync"// Parallelize parallelizes the function callsfunc Parallelize(functions ...func()) {&nbsp; &nbsp; var waitGroup sync.WaitGroup&nbsp; &nbsp; waitGroup.Add(len(functions))&nbsp; &nbsp; defer waitGroup.Wait()&nbsp; &nbsp; for _, function := range functions {&nbsp; &nbsp; &nbsp; &nbsp; go func(copy func()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer waitGroup.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; copy()&nbsp; &nbsp; &nbsp; &nbsp; }(function)&nbsp; &nbsp; }}所以在你的情况下,我们可以这样做func main() {&nbsp; &nbsp; functions := []func(){}&nbsp; &nbsp; for i := 1; i <= 5; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; function := func(i int) func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }(i)&nbsp; &nbsp; &nbsp; &nbsp; functions = append(functions, function)&nbsp; &nbsp; }&nbsp; &nbsp; Parallelize(functions...)&nbsp; &nbsp; fmt.Println("Done")}如果你想使用 Parallelize 功能,你可以在这里找到它https://github.com/shomali11/util
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go