Golang,与当地地图的竞争条件

sh *_* sh 5 go race-condition goroutine

我似乎并不完全理解Go中的地图.

我有这个代码:

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)
}
Run Code Online (Sandbox Code Playgroud)

现在,无论threadfunc函数使用fetchlocal变量,Go(go -race)都会发出警告:数据竞争.我也有一些恐慌.但为什么?fetchlocal变量不被任何其他goroutine使用.

有人可以开导我吗?

voi*_*gic 3

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

要成为一场竞赛,threadfunc必须改变 内的值fetchlocal,或者必须有其他东西改变 内的值fetch

这就是说切片实际上是:

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}
Run Code Online (Sandbox Code Playgroud)

当您将元素从一个映射复制到另一个映射时,您并没有对切片进行深层复制(您只是使用相同的 Data、Len、Cap 创建一个新结构),也就是说fetch["foo"].Data == fetchlocal["foo"].Data

因此你可以说fetch[someExistingKey] = someNewValueand 这不会与 比赛threadfunc,但如果你说fetch[someExistingKey][x] == foobarorfetchlocal[someExistingKey][x] == foobar比赛将会进行。

如果fetchlocal需要改变,threadfunc您可以将内部循环更改为:

for key, value := range fetch {
    if condition {
        newVal := make([]int, len(value))
        copy(newVal, val)
        fetchlocal[key] = newVal
    }
}
Run Code Online (Sandbox Code Playgroud)

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

threadfuncPS如果您分享了在这两个循环运行时正在修改的实际代码或代码fetch,我们将能够提供更多帮助。