我似乎并不完全了解Go中的 map 。

我有以下代码:

fetch := map[string]int{some data}

for condition {
    fetchlocal := map[string]int{}

    for key, value := range fetch {
        if condition {
            fetchlocal[key] = value
        }
    }

    go threadfunc (fetchlocal)
}

现在,无论threadfunc函数在何处使用fetchlocal变量,Go(go -race)都警告:数据争用。我也已经有些 panic 了。但为什么?其他任何goroutine都不使用fetchlocal变量。

有人可以启发我吗?

最佳答案

我假设您的fetch := map[string]int{some data}实际上应该是:fetch := map[string][]int{..some data..}

要使其成为种族,threadfunc必须更改fetchlocal中的值,或者其他必须更改fetch中的值。

也就是说, slice 实际上是:

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

当您将元素从一个映射复制到另一个映射时,不是对 slice 进行深度复制(您只是使用相同的Data,Len,Cap创建一个新结构),即fetch["foo"].Data == fetchlocal["foo"].Data

因此,您可以说fetch[someExistingKey] = someNewValue,这将不会与threadfunc竞争,但是如果您说fetch[someExistingKey][x] == foobarfetchlocal[someExistingKey][x] == foobar,竞争将继续进行。

如果fetchlocal需要被threadfunc突变,则​​可以将内部循环更改为:
for key, value := range fetch {
    if condition {
        newVal := make([]int, len(value))
        copy(newVal, val)
        fetchlocal[key] = newVal
    }
}

或者,在进行变异之前,根据需要在threadfunc中进行复制。

附言如果您在这两个循环运行时共享了实际的threadfunc或正在修改fetch的代码,我们将为您提供更多帮助。

关于go - golang ,比赛状况与本地 map ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22987426/

10-13 03:07