Golang遍歷map的同時併發修改map的值

2021-10-03 22:00:19 字數 2842 閱讀 9113

通過複製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...