sync.Map 是內建的併發安全字典,針對特定使用模式做了最佳化。

基本操作#

var m sync.Map

// 儲存
m.Store("key", "value")

// 載入
value, ok := m.Load("key")
if ok {
    fmt.Println(value.(string))
}

// 載入或儲存(若不存在則儲存)
actual, loaded := m.LoadOrStore("key2", "default")

// 刪除
m.Delete("key")

// 遍歷
m.Range(func(key, value interface{}) bool {
    fmt.Printf("%v: %v\n", key, value)
    return true  // 回 false 可中斷遍歷
})

鍵型別限制#

sync.Map 的鍵型別不能是:

  • 函式型別
  • 字典型別
  • 切片型別

違反此規則會在執行時期 panic。

型別安全封裝#

sync.Mapinterface{} 作為鍵值型別,建議外層封裝出型別安全的 API:

type IntStringMap struct {
    m sync.Map
}

func (m *IntStringMap) Store(key int, value string) {
    m.m.Store(key, value)
}

func (m *IntStringMap) Load(key int) (string, bool) {
    v, ok := m.m.Load(key)
    if !ok {
        return "", false
    }
    return v.(string), true
}

func (m *IntStringMap) Delete(key int) {
    m.m.Delete(key)
}

sync.Map vs map + Mutex#

特性sync.Mapmap + Mutex
適用場景讀多寫少、鍵穩定通用場景
效能讀取最佳化、減少鎖競爭穩定但有鎖開銷
型別安全需要型別斷言編譯時期檢查
記憶體較高(維護兩份資料)較低

何時使用 sync.Map

  1. 鍵值對只增不減或很少刪除
  2. 讀操作遠多於寫操作
  3. 不同 goroutine 操作不同的鍵

其他情況直接用 map + sync.RWMutex 即可,反而更清晰、效能也不會差。