循环时goroutine中的值不正确

时间:2017-03-07 10:43:53

标签: go

我已阅读CommonMistakes以及通过-race标志运行我的代码,但我似乎无法确定此处的错误:

package main

import (
    "fmt"
)

func main() {
    i := 1
    totalHashFields := 6
    for i <= totalHashFields {
        Combinations(totalHashFields, i, func(c []int) {
            fmt.Println("Outside goroutine:", c)
            go func(c []int) {
                fmt.Println("Inside goroutine:", c)
            }(c)
        })
        i++
    }
}

func Combinations(n, m int, emit func([]int)) {
    s := make([]int, m)
    last := m - 1
    var rc func(int, int)
    rc = func(i, next int) {
        for j := next; j < n; j++ {
            s[i] = j
            if i == last {
                emit(s)
            } else {
                rc(i+1, j+1)
            }
        }
        return
    }
    rc(0, 0)
}

(组合函数是感兴趣的人的组合algo

以下是fmt.Println的一些输出:

Outside goroutine: [0 1 4]
Inside goroutine: [5 5 5]
Outside goroutine: [0 1 2 3 4 5]
Inside goroutine: [5 5 5 5 5 5]

基本上,即使我将c作为参数传递给我的匿名go函数,该值也始终与此范围之外的值不同。在上面的输出中,我预计2&#34; Inside&#34;值也是[0 1 4]和[0 1 2 3 4 5]。

1 个答案:

答案 0 :(得分:2)

问题在于你在distinc int slice上做了很多工作,但这些工作共享一个共同的支持数组:完成Combinations后,切片s将充满5个。您的c in main与s共享底层后备阵列。

但是你的goroutines在Combinations完成之前不会开始执行,所以一旦它们开始,它将看到s的最终值,这只是5秒。

这里传递切片并没有像你所做的那样,因为这样做了c的正确副本而不是后备数组。

尝试

Combinations(totalHashFields, i, func(c []int) {
    fmt.Println("Outside goroutine:", c)
    cpy := make([]int, len(c))
    copy(cpy, c)
    go func(c []int) {
        fmt.Println("Inside goroutine:", c)
    }(cpy)
})

制作&#34;深拷贝&#34; c。