2017-02-24 38 views
-4

以下演示示例以簡單的方式顯示了我已定義的內容。我將一個映射作爲一個複製值傳遞給一個函數(而不是一個引用),以及在我的函數中存在一個遞歸,我也假設這個遞歸也是通過了值的。併發映射在沒有併發時進行讀寫

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

Go是什麼版本?那堆棧跟蹤完成了嗎? – hobbs

+0

go版本go1.6.3 linux/amd64 由於各種併發性,堆棧跟蹤非常大。 interst(恐慌的頂部)的部分就是上面的。 dataMap是按值傳遞的。我認爲這不會導致併發問題。 – gextra

+0

我在這裏添加了完整的跟蹤https://play.golang.org/p/p75UITydVP – gextra

回答

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,因此請運行比賽檢測器。

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. 

此外,編譯和使用1.8圍棋,圍棋,這顯著提高了併發圖濫用的當前版本運行程序。

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.