golang_並發安全: slice和map並發不安全及解決方法
Grayan · 2020-07-21 15:32:48 · 1771 次點擊 · 預計閱讀時間 1 分鍾 · 不到1分鍾之前 開始瀏覽
這是一個創建於
2020-07-21 15:32:48 的文章,其中的信息可能已經有所發展或是發生改變。
並發安全
並發安全也叫線程安全,在並發中出現了數據的丟失,稱為並發不安全
map和slice都是並發不安全的
切片並發不安全
場景: 10000個協程同時添加切片
var s []int func appendValue(i int) { s = append(s, i) } func main() { for i := 0; i < 10000; i++ { //10000個協程同時添加切片 go appendValue(i) } for i, v := range s { //同時打印索引和值 fmt.Println(i, ":", v) } }
Output:
沒有到9999,說明有數據丟失
解決方法: 加鎖
var s []int var lock sync.Mutex //互斥鎖 func appendValue(i int) { lock.Lock() //加鎖 s = append(s, i) lock.Unlock() //解鎖 } func main() { for i := 0; i < 10000; i++ { go appendValue(i) } //sort.Ints(s) //給切片排序,先排完序再打印,和下面一句效果相同 time.Sleep(time.Second) //間隔1s再打印,防止一邊插入數據一邊打印時數據亂序 for i, v := range s { fmt.Println(i, ":", v) } }
總結: slice在並發執行中不會報錯,但是數據會丟失
map並發不安全
場景: 2個協程同時讀和寫
func main() { m := make(map[int]int) go func() { //開一個協程寫map for i := 0; i < 10000; i++ { m[i] = i } }() go func() { //開一個協程讀map for i := 0; i < 10000; i++ { fmt.Println(m[i]) } }() //time.Sleep(time.Second * 20) for { ; } }
Output:
解決方法:盡量不要做map的並發,如果用並發要加鎖,保證map的操作要么讀,要么寫。
var lock sync.Mutex func main() { m:=make(map[int]int) go func() { //開一個協程寫map for i:=0;i<10000 ;i++ { lock.Lock() //加鎖 m[i]=i lock.Unlock() //解鎖 } }() go func() { //開一個協程讀map for i:=0;i<10000 ;i++ { lock.Lock() //加鎖 fmt.Println(m[i]) lock.Unlock() //解鎖 } }() time.Sleep(time.Second*20) }
總結: map在並發執行中會直接報錯