我似乎完全不了解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)
}
现在,无论threadfunc函数使用fetchlocal变量,Go(go -race)都会发出警告:数据竞争。我也有一些恐慌。但为什么? fetchlocal变量不被任何其他goroutine使用。
有人可以开导我吗?
答案 0 :(得分:1)
我假设您的fetch := map[string]int{some data}
实际上应该是:fetch := map[string][]int{..some data..}
。
要成为比赛,threadfunc
必须更改fetchlocal
内的值,否则必须更改fetch
内的值。
这就是切片实际上是:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
当您将元素从一个地图复制到另一个地图时,您不执行切片的深层复制(您只是创建一个具有相同数据,Len,Cap的新结构),如此说fetch["foo"].Data == fetchlocal["foo"].Data
。
因此,您可以说fetch[someExistingKey] = someNewValue
这不会与threadfunc
竞争,但如果您说fetch[someExistingKey][x] == foobar
或fetchlocal[someExistingKey][x] == foobar
,竞赛将会开始。
如果fetchlocal
需要threadfunc
进行变异,您可以将内循环更改为:
for key, value := range fetch {
if condition {
newVal := make([]int, len(value))
copy(newVal, val)
fetchlocal[key] = newVal
}
}
或者,在变异之前根据需要在threadfunc
内进行复制。
P.S。如果您在这两个循环运行时共享了实际threadfunc
或正在修改fetch
的代码,我们将能够提供更多帮助。