golang 中实现并发安全的map

编辑于 2022-10-12 16:26:26 阅读 905

Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的。

问题还原

下面来看下并发情况下读写 map 时会出现的问题

func main() {
	m := make(map[int]int)
	go func() {
		// 不停地对map进行写入
		for {
			m[1] = 1
		}
	}()

	go func() {
		// 不停地对map进行读取
		for {
			_ = m[1]
		}
	}()
}

会报错

fatal error: concurrent map read and map write

实现方案1 - 加锁

// 加锁的map
type Map struct {
	m map[int]int
	sync.RWMutex
}

func (this *Map) Get(key int) int {
	this.RLock()
	defer this.RUnlock()

	v := this.m[key]
	return v
}

func (this *Map) Set(k, v int) {
	this.Lock()
	defer this.Unlock()

	this.m[k] = v
}

func main() {
	newMap := &Map{m: make(map[int]int)}
	for i := 0; i < 1000; i++ {
		go newMap.Set(i, i)
	}
	for i := 0; i < 1000; i++ {
		go fmt.Println(i, newMap.Get(i))
	}

	time.Sleep(time.Second)
}

实现方案2 - sync.Map

type Map struct
func (m *Map) Store(key, value interface{})
func (m *Map) Load(key interface{}) (value interface{}, ok bool)
func (m *Map) Range(f func(key, value interface{}) bool)
func (m *Map) Delete(key interface{})

sync.Map 有以下特性:

  • 无须初始化,直接声明即可。
  • sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。
  • 使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。
  • LoadOrStore:参数是一对key:value,如果该key存在且没有被标记删除则返回原先的value(不更新)和true;不存在则store,返回该value 和false
func main() {
	var m sync.Map
	m.Store("bb", 22)
	m.Store("cc", 33)
	m.Store("aa", 11)
	m.Store("dd", 33)
	m.Store("ee", 11)

	//Load 方法,获得value
	if v, ok := m.Load("cc"); ok {
		fmt.Printf("Load 方法,获得value   %v: %v\n", v, ok)
	}
	m.Delete("cc")

	//LoadOrStore方法,获取或者保存
	//就是如果key还在,那么就保持原来并返回原来的值,如果key不存在就存储
	if vv, ok := m.LoadOrStore("bb", 22); ok {
		fmt.Println(vv)
	} else {
		fmt.Printf("LoadOrStore 方法,获得value   %v: %v\n", vv, ok)
	}

	//遍历该map
	m.Range(func(key, value interface{}) bool {
		fmt.Printf("[%v]=[%v]\n", key, value)
		return true
	})
}

实现方案3 - 分段锁

未完,待续。。。

参考

https://blog.csdn.net/zhizhengguan/article/details/107879969

https://blog.csdn.net/lanyang123456/article/details/114178724

广而告之,我的新作品《语音助手》上架Google Play了,欢迎下载体验