golang中map並發讀寫問題及解決方法
一、map並發讀寫問題
如果map由多協程同時讀和寫就會出現 fatal error:concurrent map read and map write的錯誤
如下代碼很容易就出現map並發讀寫問題
func main(){
c := make(map[string]int)
go func() {//開一個協程寫map
for j := 0; j < 1000000; j++ {
c[fmt.Sprintf("%d", j)] = j
}
}()
go func() { //開一個協程讀map
for j := 0; j < 1000000; j++ {
fmt.Println(c[fmt.Sprintf("%d",j)])
}
}()
time.Sleep(time.Second*20)
}
多個協程同時寫也會出現fatal error: concurrent map writes的錯誤
如下代碼很容易出現map並發寫的問題
func main(){
c := make(map[string]int)
for i := 0; i < 100; i++ {
go func() { //開100個協程並發寫map
for j := 0; j < 1000000; j++ {
c[fmt.Sprintf("%d", j)] = j
}
}()
}
time.Sleep(time.Second*20) //讓執行main函數的主協成等待20s,不然不會執行上面的並發操作
}
二、出現問題的原因
因為map為引用類型,所以即使函數傳值調用,參數副本依然指向映射m, 所以多個goroutine並發寫同一個映射m, 寫過多線程程序的同學都知道,對於共享變量,資源,並發讀寫會產生競爭的, 故共享資源遭到破壞
三、解決方法
1、加鎖
(1)通用鎖
type Demo struct {
Data map[string]string
Lock sync.Mutex
}
func (d Demo) Get(k string) string{
d.Lock.Lock()
defer d.Lock.UnLock()
return d.Data[k]
}
func (d Demo) Set(k,v string) {
d.Lock.Lock()
defer d.Lock.UnLock()
d.Data[k]=v
}
(2)讀寫鎖
type Demo struct {
Data map[string]string
Lock sync.RwMutex
}
func (d Demo) Get(k string) string{
d.Lock.RLock()
defer d.Lock.RUnlock()
return d.Data[k]
}
func (d Demo) Set(k,v string) {
d.Lock.Lock()
defer d.Lock.UnLock()
d.Data[k]=v
}
2、利用channel串行化處理
golang中map並發讀寫問題及解決方法