当没有并发时,同时读写并发映射。

huangapple go评论85阅读模式
英文:

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。

Go 1.6 Release Notes

运行时

运行时已经添加了轻量级的、尽力检测并发地错误使用 map 的功能。一如既往,如果一个 goroutine 正在写入一个 map,其他 goroutine 不应该同时读取或写入该 map。如果运行时检测到这种情况,它会打印出诊断信息并使程序崩溃。了解更多问题的最佳方法是在 race detector 下运行程序,它将更可靠地识别出竞争条件并提供更多细节。

Command go

编译包及其依赖项

-race
    启用数据竞争检测。
    仅支持 linux/amd64、freebsd/amd64、darwin/amd64 和 windows/amd64。

此外,使用当前版本的 Go,即 Go 1.8,编译和运行你的程序,它显著改进了并发 map 的错误使用。

Go 1.8 Release Notes

并发 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.

huangapple
  • 本文由 发表于 2017年2月24日 17:07:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/42434658.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定