英文:
Golang, race condition with local map
问题
我似乎并不完全理解Go语言中的地图(maps)。
我有以下代码:
fetch := map[string]int{一些数据}
for 条件 {
fetchlocal := map[string]int{}
for 键, 值 := range fetch {
if 条件 {
fetchlocal[键] = 值
}
}
go 线程函数(fetchlocal)
}
现在,无论线程函数(threadfunc)在哪里使用fetchlocal变量,Go(go -race)都会显示警告:数据竞争(data race)。我已经遇到了一些恐慌。但是为什么呢?fetchlocal变量没有被任何其他goroutine使用。
有人可以给我解释一下吗?
英文:
I don't seem to totally understand maps in Go.
I have this code:
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)
}
Now wherever the threadfunc function uses the fetchlocal variable Go (go -race) says warning: data race. I also got a few panics already. But why? The fetchlocal variable isn't used by any other goroutine.
Can someone enlighten me, please?
答案1
得分: 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
}
当你将元素从一个映射复制到另一个映射时,你并没有对切片进行深拷贝(你只是创建了一个具有相同Data、Len、Cap的新结构体),也就是说fetch["foo"].Data == fetchlocal["foo"].Data
。
因此,你可以说fetch[someExistingKey] = someNewValue
,这不会与threadfunc
竞争,但如果你说fetch[someExistingKey][x] == foobar
或fetchlocal[someExistingKey][x] == foobar
,就会出现竞争。
如果threadfunc
需要修改fetchlocal
,你可以将内部循环更改为:
for key, value := range fetch {
if condition {
newVal := make([]int, len(value))
copy(newVal, val)
fetchlocal[key] = newVal
}
}
或者,在修改之前,在threadfunc
内部根据需要进行复制。
附注:如果你分享了实际的threadfunc
或在这两个循环运行时修改fetch
的代码,我们将能够提供更多帮助。
英文:
I'm assuming your fetch := map[string]int{some data}
was actually supposed to be: fetch := map[string][]int{..some data..}
.
For this to be a race threadfunc
must be changing a value within fetchlocal
or something else must be changing the value within fetch
.
This is to say a slice is a actually:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
When you are copying the elements from one map to another you are not doing a deep copy of the slices (you are just creating a new struct with the same Data,Len,Cap), that is so say fetch["foo"].Data == fetchlocal["foo"].Data
.
Therefore you can say fetch[someExistingKey] = someNewValue
and this will not race with threadfunc
, but if you say fetch[someExistingKey][x] == foobar
or fetchlocal[someExistingKey][x] == foobar
the race will be on.
If fetchlocal
needs to mutated by threadfunc
you could change your inner loop to look like:
for key, value := range fetch {
if condition {
newVal := make([]int, len(value))
copy(newVal, val)
fetchlocal[key] = newVal
}
}
Or alternatively, do the copy inside threadfunc
as needed before mutating.
P.S. If you shared your actual threadfunc
or code that is modifying fetch
while these two loops are running, we will be able to help more.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论