【Go学习】语言类库(三)sync.Map

81 阅读1分钟

前面讲到,Go中Map不是并发安全的(体现为操作前需要读flag),而Go1.19开始引入了sync.Map,这是一种同步的Map,是并发安全的。

用法

package main

import (
   "fmt"
   "sync"
)

func main() {
   var m sync.Map
   //增加,对应于java的put
   m.Store("xiaoming", 19)
   m.Store("xiaohong", 30)

   //查,对应于get
   age, _ := m.Load("xiaoming")
   fmt.Println(age.(int))

   //对应于getOrDefault()
   m.LoadOrStore("lan", 100)
   ages, _ := m.Load("lan")
   fmt.Println(ages)

   //遍历
   m.Range(func(key, value interface{}) bool {
      name := key.(string)
      age := value.(int)
      fmt.Println(name, age)
      return true
   })

   //删除,对应于remove()
   m.Delete("xiaoming")
   age, ok := m.Load("xiaoming")
   fmt.Println(age, ok)
   
}

使用场景

image.png

  • 原生的map使用的时候需要加锁,不过一般情况下出于对类型安全的考虑,原生的就够用了。sync包下的map不用加锁,而是通过信号量mutex。两种情况下用它比较多:
    • 一次写入,多次读取
    • 多个协程读/写/覆盖不相交的键值集合

底层实现

type Map struct {
   mu Mutex

   //注意如果要更新一个之前已被删除的entry,需先将其状态改为nil,再复制到dirty中,再更新
   //不加锁,保证原子性
   read atomic.Value // readOnly

  //类型是原始的map,包含新写入的key和read中所有未被删除的key,可快速将dirty提升为read对外服务
  //加锁
   dirty map[any]*entry

  //每次读取read失败,misses值+1,到达阈值后提升dirty为read
   misses int
}