通過複製map解決問題
後記如題,有個邏輯設計,在遍歷map的同時需要併發的修改map的值
先說下解決,那就是把map重新複製乙份,不是同乙個map自然也就不存在併發安全和死鎖的問題了,但是因為不是同乙個map了,自然是需要注意資料還是否有效的問題了。這個可以通過加鎖之後的再次判斷來解決。
併發的讀寫map會出現panic:fatal error: concurrent map iteration and map write
因為既要通過range進行遍歷,又要在另乙個goroutine中進行修改,所以range的時候沒法加鎖,因為修改的時候要加鎖,如果在range的整個過程加鎖,那具體的修改時候就會造成死鎖
也考慮過 go1.9 之後提供的 sync.map,但是這個型別沒有獲取map長度的方法,所以也沒法滿足我的需求
併發問題舉例1 - panic
package main
import
("fmt"
"strconv"
"testing"
)func
testrangemap
(t *testing.t)}(
)//遍歷map,相當於讀
for k, v :=
range tmpmap
}
結果:
==
= run testrangemap
1 12 2
fatal error: concurrent map iteration and map write
goroutine 33 [running]:
runtime.throw(0x113fe01, 0x26)
....
..
併發問題舉例2 - 死鎖package main
import
("strconv"
"sync"
"testing"
)type datamap struct
func
changemap
(data datamap)
func
testrangemap
(t *testing.t),}
data.data[1]
="1"
data.data[2]
="2"
data.data[3]
="3"
data.data[4]
="4"
wg :=
&sync.waitgroup
wg.add(1)
gofunc()
}() wg.
wait()
}
結果:
==
= run testrangemap
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
testing.(*t).run(0xc0000c8100, 0x113ae67, 0xc, 0x11427a8, 0x1069e26)
....
..
/**
* created with goland
* user: zhuxinquan
* date: 2018-12-06
* time: 下午6:11
**/package main
import
("strconv"
"sync"
"testing"
)type datamap struct
func
changemap
(data datamap)
func
testrangemap
(t *testing.t),}
data.data[1]
="1"
data.data[2]
="2"
data.data[3]
="3"
data.data[4]
="4"
wg :=
&sync.waitgroup
wg.add(1)
tmpmap :=
make
(map
[int
]string
)//複製map, 複製之前加鎖
data.mux.
lock()
for k, v :=
range data.data
data.mux.
unlock()
gofunc()
}() wg.
wait()
}
結果:
==
= run testrangemap
--- pass: testrangemap (0.00s)
pass
process finished with exit code 0
沒有異常了!
map併發是不安全的,加鎖需要謹慎注意死鎖的問題,range操作是對map的讀,同時併發的讀寫會panic,以上覆制的方案只是繞過了同時讀寫的問題,但是就變成了兩個map了,所以需要在具體操作之前校驗下資料的正確性(可能已經失效),具體操作的時候,因為是加鎖之後再進行的操作,所以相對來說,校驗有效性就根據具體邏輯來做就行。
sync.map 沒有length方法真的比較雞肋, 最起碼我現在1.12.7的版本還沒有,不知道後面go官方是否會實現這個方法。
mysql遍歷map中的陣列 遍歷Map的四種方法
public static void main string args map map new hashmap map.put 1 value1 map.put 2 value2 map.put 3 value3 第一種 普遍使用,二次取值 system.out.println 通過map.keys...
golang 中 map 的使用
golang 中 map 的初始化方式 1 先宣告 map var m1 map int int 再使用make函式建立乙個非nil的map,nil map不能賦值 m1 make map int int 賦值 m1 66 55fmt.println m1 map 66 55 2 直接 make 建...
Map遍歷的方法
一.遍歷方法 1.只遍歷value for string value map.values 2.keyset遍歷key和value for string key map.keyset 3.entryset使用iterator遍歷key和value iterator it map.entryset i...