sync.Map與Concurrent Map

1. sync.Map

1.1. map併發不安全

go1.6之後map有了併發的安全檢查,因此若是在併發環境中讀寫map就會報錯html

func unsafeMap()  {
    // 建立一個map對象
	m := make(map[int]int)
	go func() {
		for {
            // 嘗試讀取數據
			_ = m[1]
		}
	}()
	go func() {
		for {
            // 嘗試寫入數據
			m[2] = 2
		}
	}()
    // 阻塞
	select {}
}

// output
// fatalerror: concurrent map read and map write

1.2 安全map

 併發環境下面使用安全的mapjava

1.2.1 自定義結構體

// 經過內嵌讀寫鎖的方式,保證咱們使用map的安全性
type MyMap struct{
	sync.RWMutex
    m map[string]int  // 須要一個併發的map[string]int類型
}

// 封裝一個建立map對象的方法
func NewMyMap()*MyMap{
    smp:=new(MyMap)
    smp.m = make(map[string]int)
    return smp
} 

注意:咱們定義使用什麼類型的map,那麼就內置什麼類型的map git

1.2.2 sync.Map

go1.9之後sync包中加入了安全的map對象,,syn.Map不支持普通的map操做,須要使用sync.Map提供的api使用github

    • 建立sync.Map對象golang

      //1. 不須要經過map的方式進行建立,經過聲明的方式或者new建立便可
      var smap sync.Map
      
      //2. 經過new的方式建立
      smap:=new(sync.Map)
    • sync.Map 存儲數據store方法api

      //func (m *Map) Store(key, value interface{})
      // key,value 都是接口類型,能夠存儲任何類型的數據
      smap.Store(1,"MrSun") 
    • sync.Map讀取數據安全

      // func (m *Map) Load(key interface{}) (value interface{}, ok bool)
      // key: 鍵,value: 若是數據存在則返回對應的值,不存在則返回nil,ok: 表示值知否被找到
      // 記得對數據斷言處理
      val,ok:=smap.Load(1)
    • sync.Map,存在則讀取,不存在存儲併發

      // func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
      // key,value: 要存儲的key與value
      //actual: 若是存在則返回存在的值,若是不存在則存儲並返回存儲的值
      // laoded: 若是數據存在,則true,若是數據不存在則false
      actual, loaded := smap.LoadOrStore(1, "MrSun")
    • sync.Map 遍歷函數

      // 建立map
      smap:=new(sync.Map)
      smap.LoadOrStore(1, "MrSun")
      smap.LoadOrStore(2, "hello")
      smap.LoadOrStore(3, "golang")
      smap.LoadOrStore(4, "bilili")
      //func (m *Map) Range(f func(key, value interface{}) bool)
      // 用戶處理數據的回調函數,回調函數的參數是key,value,返回值是bool
      smap.Range(func(key, value interface{}) bool {
      		smap.Store(5,"heihei")
      		fmt.Println(key,value)
      		return true
      }) 

      // 注意:Range方法遍歷的是map的副本
  • sync.Map 數據刪除
  • // func (m *Map) Delete(key interface{})
    // key: 要刪除數據的key值
    smap.Delete(1)
    

     

1.2.3 sync.Map與內置讀寫鎖性能對比

 

 

  • 4核心之前內置的讀寫鎖map性能要高高併發

  • 4核心後,sync.Map 性能要高

  • sync.Map 性能穩定

1.2.4 sync.Map使用場景

The Map type is optimized for two common use cases:

  1. when the entry for a given key is only ever written once but read many times, as in caches that only grow.

  2. when multiple goroutines read, write, and overwrite entries for disjoint sets of keys. In these two cases, use of a Map may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.

  • 寫少讀多的狀況

  • 多goroutine,讀、寫、複寫 不一樣數據的狀況 【沒遇到過】

  • 多核心狀況使用

建議:沒有特別要求的狀況,二者均可以,go1.9之後建議直接使用sync.Map

 

1.2.5 sync.Map源碼剖析

sync.Map

2. Concurrent Map

併發安全map,相似java下面的java.util.ConcurrentHashMap,適合讀寫都相對比較頻繁的狀況

2.1 基本原理

採用分段鎖機制,從而提升併發安全的性能

 

 

2.2 concurrent map下載

 

# github 星標 最高的一個
go get "github.com/orcaman/concurrent-map"

2.2 基本使用

不一樣的第三方包模塊使用API都不同,使用那個模塊須要查看對應模塊的文檔

import "github.com/orcaman/concurrent-map"

func concurrentMap()  {
	mp:=cmap.New()
	// 存儲值,key只能是string類型,value能夠是任意類型
	mp.Set("1","hello")
	mp.Set("2","golang")
    //val: 若是存在則返回值,不存在則返回nil
    // ok: 表示值若是存在則是true,若是不存在則是false
	val,ok:=mp.Get("2")
	if ok{
		fmt.Println(val.(string))
	}
	mp.Remove("1")
	_,ok=mp.Get("1")
	if !ok{
		fmt.Println("data is not exist")
	}
}
相關文章
相關標籤/搜索