sync.WaitGroup and nested loops

你离开我真会死。 提交于 2020-01-25 06:49:13

问题


I'd like to add concurrency for iterating nested loops but having a trouble. What's wrong with this example usage of sync.WaitGroup?

originCities := [3]string{"LED", "MOW", "PRS"}
destinationCities := [2]string{"UKT", "AAC"}

wg := &sync.WaitGroup{}
wg.Add(len(originCities) * len(destinationCities))

for _, originIata := range originCities {
    for _, destinationIata := range destinationCities {
        go func () {
            fmt.Println(originIata)
            fmt.Println(destinationIata)
            wg.Done()
        }()
    }
}
wg.Wait()

I'm getting

PRS AAC PRS AAC PRS AAC PRS AAC PRS AAC PRS AAC

So as you may see it's skipping first elements of both array and iterating only the last ones. Any ideas how to fix this behavior?


回答1:


It's a closure problem. You need to pass values to your goroutine inside the loop, like this:

for _, originIata := range originCities {
    for _, destinationIata := range destinationCities {
        go func (originIata, destinationIata string) {
            fmt.Println(originIata)
            fmt.Println(destinationIata)
            wg.Done()
        }(originIata, destinationIata)
    }
}



回答2:


As has been posted, one can pass the values as function parameters to the goroutine function.

Or one can use the technique of creating explicit variables within the scope of the loops. For simplicity, you can reuse the same variable name. This ensures the goroutine references the for loop's closure value (and not the externally-scoped dynamic value you were experiencing):

for _, originIata := range originCities {
    originIata := originIata // here
    for _, destinationIata := range destinationCities {
        destinationIata := destinationIata // here
        go func () {
            fmt.Println(originIata)
            fmt.Println(destinationIata)
            wg.Done()
        }()
    }
}

Note: the above fix will only work, if the copies are done outside the goroutine function.


Edit: use go tools like go vet and go's race-detector to help catch these gotcha type bugs.

For example, the go playground (as well as popular editors like VScode) run go vet by default e.g.

https://play.golang.org/p/JhALssCu2-T

But note, do not rely on go vet as a security blanket. In the playground above, it does not catch the outer o potential race condition.

You can build your executable with a data-race detector (tl;dr; go build -race ; use this for testing and not production - as it performs slower and has something like a 8K go-routine limit).

The race-detector will only catch data-races issues at runtime. So use it judiciously, as it is not a code-flow analyzer and thus cannot predict any future potential code execution issues.



来源:https://stackoverflow.com/questions/58533613/sync-waitgroup-and-nested-loops

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!