背景
go中map數據結構不是線程安全的,即多個goroutine同時操作一個map,則會報錯,因此go1.9之後誕生了sync.Map
sync.Map思路來自java的ConcurrentHashMap
接口
sync.map就是1.9版本帶的線程安全map,主要有如下幾種方法:
Load(key interface{}) (value interface{}, ok bool) //通過提供一個鍵key,查找對應的值value,如果不存在,則返回nil。ok的結果表示是否在map中找到值 Store(key, value interface{}) //這個相當於是寫map(更新或新增),第一個參數是key,第二個參數是value LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) //通過提供一個鍵key,查找對應的值value,如果存在返回鍵的現有值,否則存儲並返回給定的值,如果是讀取則返回true,如果是存儲返回false Delete(key interface{}) //通過提供一個鍵key,刪除鍵對應的值 Range(f func(key, value interface{}) bool) //循環讀取map中的值。 //因為for ... range map是內置的語言特性,所以沒有辦法使用for range遍歷sync.Map, 但是可以使用它的Range方法,通過回調的方式遍
實踐
package main import ( "fmt" "sync" ) var num = 0 var addTest *AddTest func init() { addTest = &AddTest{} } type AddTest struct { m sync.Mutex } func (at *AddTest) increment(wg *sync.WaitGroup) { //互斥鎖 at.m.Lock() //當有線程進去進行加鎖 num++ at.m.Unlock() //出來後解鎖,其他線程才可以進去 wg.Done() } func (at *AddTest) decrement(wg *sync.WaitGroup) { //互斥鎖 at.m.Lock() //當有線程進去進行加鎖 num-- at.m.Unlock() //出來後解鎖,其他線程才可以進去 wg.Done() } var w sync.WaitGroup var aa map[int]int func main() { var bb sync.Map var wg sync.WaitGroup //aa = make(map[int]int) wg.Add(2) go func() { //wg.Add(1) for i:=0 ;i<100; i++{ //aa[i] = i+1 //fmt.Println("a") bb.Store(i, i+1) } wg.Done() }() go func() { for i:=0 ;i <100; i++{ //aa[i] = i+1 //fmt.Println("a") bb.Store(i, i+1) } wg.Done() }() wg.Wait() bb.Range(func(k, v interface{}) bool { fmt.Println("iterate:", k, v) return true } }
總結
讀寫鎖和互斥鎖 讀寫鎖: 可以獲取多個讀鎖,只有讀寫衝突(加了讀鎖的時候,其它線程不能寫) 互斥鎖:跟讀寫操作無關,加了鎖,鎖內的資源就線程獨享
個人感覺使用起來不太方便,不如根據實際場景自己互斥鎖。比如map都是可讀的,只有寫的時候需要串行執行,則寫操作封裝互斥鎖即可
sync.Map因為內部的操作較多等原因,並不適合大量寫的場景(適合大量讀,少量寫)。
sync.Map的原理自行学习
參考
https://www.kancloud.cn/liupengjie/go/718991
https://colobu.com/2017/07/11/dive-into-sync-Map/
[retouched ] golang中使用sync.Map的方法已經有245次圍觀