英文:
concurrent map read and write when there is no concurrency
问题
以下是翻译的内容:
下面的示例以简单的方式展示了我所定义的内容。我将一个地图作为复制的值传递给一个函数(而不是引用),并且在我的函数中有一个递归,我假设它也是通过值传递的。
问题:在我的程序执行过程中,涉及的数据比这个示例要多得多(显然),出现了一个错误“fatal error: concurrent map read and map write”,指向函数findParentAncestors():
// 这个函数对dataMap没有写操作,只是读取
// dataMap实际上没有写操作,因为它是复制的
func findParentAncestors(ID int, dataMap map[int]Data) []Data {
results := []Data{}
if _, ok := dataMap[ID]; ok {
if parentData, ok := dataMap[dataMap[ID].ParentID]; ok {
results = append(results, parentData)
// 递归
results = append(results, findParentAncestors(parentData.ID, dataMap)...)
}
}
return results
}
希望这能帮到你!
英文:
The following go play example shows in a simplistic way what I have defined. I am passing a map as a copied value to a function (not a reference) as well as there is a recursion in my function which I assume passes by value as well.
https://play.golang.org/p/na6y6Wih4M
// this function has no write operations to dataMap, just reads
// dataMap, in fact, has no write operations since it was copied
func findParentAncestors(ID int, dataMap map[int]Data) []Data {
results := []Data{}
if _, ok := dataMap[ID]; ok {
if parentData, ok := dataMap[dataMap[ID].ParentID]; ok {
results = append(results, parentData)
// recursion
results = append(results, findParentAncestors(parentData.ID, dataMap)...)
}
}
return results
}
PROBLEM: somehow along my program execution, which involves much more data than this example (obviusly), an error "fatal error: concurrent map read and map write" points function findParentAncestors():
main.findParentAncestors(0x39e3, 0xc82013ac90, 0x0, 0x0, 0x0)
/opt/test/src/test.go:17 +0xa6 fp=0xc820269fb8 sp=0xc820269bd0
main.findParentAncestors(0x5d25, 0xc82013ac90, 0x0, 0x0, 0x0)
/opt/test/src/test.go:21 +0x239 fp=0xc82026a3a0 sp=0xc820269fb8
答案1
得分: 2
根据你提供的内容,以下是翻译的结果:
从你的示例中,https://play.golang.org/p/na6y6Wih4M:
// the orignalMap is defined elsewhere in the program (here represented)
originalMap := map[int]Data{}
originalMap[0] = Data{ID: 0, ParentID: -1, Name: "zero"}
originalMap[1] = Data{ID: 1, ParentID: 0, Name: "one"}
originalMap[2] = Data{ID: 2, ParentID: 1, Name: "two"}
// copies the original map from a global location (here represented)
copiedMap := originalMap
// identifies ancestors unsing the copied map
parents := findParentAncestors(2, copiedMap)
这里的 copiedMap := originalMap
是一个误称,你并没有复制这个 map。
在 Go 中,所有的参数都是按值传递的。这相当于将每个参数分配给每个参数。对于一个 map,赋值 copiedMap := originalMap
或按值传递 findParentAncestors(2, copiedMap)
,都是复制了 map 描述符,该描述符是指向 map 描述符结构体的指针,该结构体包含指向 map 键值数据的指针。如果有任何对 map 的写操作,显然会存在潜在的竞态条件。
你正在使用的是 go version go1.6.3 linux/amd64
,所以请运行 race detector。
运行时
运行时已经添加了轻量级的、尽力检测并发地错误使用 map 的功能。一如既往,如果一个 goroutine 正在写入一个 map,其他 goroutine 不应该同时读取或写入该 map。如果运行时检测到这种情况,它会打印出诊断信息并使程序崩溃。了解更多问题的最佳方法是在 race detector 下运行程序,它将更可靠地识别出竞争条件并提供更多细节。
编译包及其依赖项
-race 启用数据竞争检测。 仅支持 linux/amd64、freebsd/amd64、darwin/amd64 和 windows/amd64。
此外,使用当前版本的 Go,即 Go 1.8,编译和运行你的程序,它显著改进了并发 map 的错误使用。
并发 Map 错误使用
在 Go 1.6 中,运行时已经添加了轻量级的、尽力检测并发地错误使用 map 的功能。此版本通过支持检测同时写入和迭代 map 的程序来改进该检测器。
一如既往,如果一个 goroutine 正在写入一个 map,其他 goroutine 不应该同时读取(包括迭代)或写入该 map。如果运行时检测到这种情况,它会打印出诊断信息并使程序崩溃。了解更多问题的最佳方法是在 race detector 下运行程序,它将更可靠地识别出竞争条件并提供更多细节。
英文:
From your example, https://play.golang.org/p/na6y6Wih4M:
// the orignalMap is defined elsewhere in the program (here represented)
originalMap := map[int]Data{}
originalMap[0] = Data{ID: 0, ParentID: -1, Name: "zero"}
originalMap[1] = Data{ID: 1, ParentID: 0, Name: "one"}
originalMap[2] = Data{ID: 2, ParentID: 1, Name: "two"}
// copies the original map from a global location (here represented)
copiedMap := originalMap
// identifies ancestors unsing the copied map
parents := findParentAncestors(2, copiedMap)
This is a misnomer, copiedMap := originalMap
, you are not copying the map.
In Go all arguments are passed by value. It's equivalent to assigning each argument to each parameter. For a map, assignment, copiedMap := originalMap
, or passing by value, findParentAncestors(2, copiedMap)
, copies the map descriptor which is a pointer to the map descriptor struct which contains a pointer to the map key-value data. Obviously you have a potential race condition if there are any writes to the map.
You are using go version go1.6.3 linux/amd64
, so run the race detector.
> Go 1.6 Release Notes
>
> Runtime
>
> The runtime has added lightweight, best-effort detection of concurrent
> misuse of maps. As always, if one goroutine is writing to a map, no
> other goroutine should be reading or writing the map concurrently. If
> the runtime detects this condition, it prints a diagnosis and crashes
> the program. The best way to find out more about the problem is to run
> the program under the race detector, which will more reliably identify
> the race and give more detail.
>
> Command go
>
> Compile packages and dependencies
>
> -race
> enable data race detection.
> Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
Also, compile and run your program using Go 1.8, the current release of Go, which significantly improves concurrent map misuse.
> Go 1.8 Release Notes
>
> Concurrent Map Misuse
>
> In Go 1.6, the runtime added lightweight, best-effort detection of
> concurrent misuse of maps. This release improves that detector with
> support for detecting programs that concurrently write to and iterate
> over a map.
>
> As always, if one goroutine is writing to a map, no other goroutine
> should be reading (which includes iterating) or writing the map
> concurrently. If the runtime detects this condition, it prints a
> diagnosis and crashes the program. The best way to find out more about
> the problem is to run the program under the race detector, which will
> more reliably identify the race and give more detail.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论