以下go play示例以简单的方式显示了我定义的内容。我将一个映射作为复制值传递给函数(不是引用),并且在我的函数中有一个递归,我假设它也是按值传递的。
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
}
问题:在某种程度上我的程序执行,涉及比这个例子(obviusly)更多的数据,错误“致命错误:并发地图读取和地图写入”指向函数 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
答案 0 :(得分: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
,你没有复制地图。
在Go中,所有参数都按值传递。它相当于为每个参数分配每个参数。对于映射,赋值,copiedMap := originalMap
或按值传递findParentAncestors(2, copiedMap)
,复制映射描述符,该映射描述符是指向包含指向映射键值数据的指针的映射描述符结构的指针。如果对地图有任何写入,显然你有潜在的竞争条件。
您正在使用go version go1.6.3 linux/amd64
,因此请运行竞赛检测器。
运行
运行时添加了轻量级,尽力而为的并发检测 滥用地图。和往常一样,如果一个goroutine正在写一张地图,没有 其他goroutine应该同时读取或写入地图。如果 运行时检测到这种情况,它会打印诊断并崩溃 该程序。了解问题的最佳方法是运行 比赛探测器下的程序,将更可靠地识别 比赛并提供更多细节。
编译包和依赖项
-race enable data race detection. Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
此外,使用Go的当前版本Go 1.8编译并运行程序,这显着改善了并发映射的误用。
并发地图滥用
在Go 1.6中,运行时添加了轻量级,尽力而为的检测功能 并发滥用地图。此版本改进了该探测器 支持检测同时写入和迭代的程序 在地图上。
与往常一样,如果一个goroutine写入地图,没有其他goroutine 应该是阅读(包括迭代)或写地图 同时。如果运行时检测到这种情况,则会打印出一个 诊断和崩溃程序。了解更多信息的最佳方式 问题是在竞赛检测器下运行程序,这将是 更可靠地识别比赛并提供更多细节。