Go Map 为啥是非线程安全的?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go Map 为啥是非线程安全的?相关的知识,希望对你有一定的参考价值。

参考技术A

Go map 默认是并发不安全的,同时对 map 进行并发读写的时,程序会 panic,原因如下:Go 官方经过长时间的讨论,认为 map 适配的场景应该是简单的(不需要从多个 gorountine 中进行安全访问的),而不是为了小部分情况(并发访问),导致大部分程序付出锁的代价,因此决定了不支持。

并发读写可能引发的问题

使用 sync.RWMutex 解决并发读写的问题

使用 sync.Map 解决并发读写的问题

实际上, sync.Map 也是通过加锁的方式实现并发安全的, sync.Map 源码的数据结构如下:

就像官方考虑的那样,我们在使用中,应尽量避免对 Map 进行并发读写,尝试通过其他方式解决问题,如数据解耦、分布执行、动态规划等,真的需要并发读写时,为避免产生并发读写的问题,请使用锁的机制进行控制

Go 实现线程安全 map 读写(sync.RWMutex)

        当然,go 语言已经内置提供了线程安全 map,即 sync.Map,

        在这里只是用自己的方式实现简单的锁应用,

        代码示例如下:

import "sync"
 
type SafeDict struct {
	data  map[string]int
	*sync.RWMutex
}
 
func NewSafeDict(data map[string]int) *SafeDict {
	return &SafeDict{data, &sync.RWMutex{}}
}
 
func (d *SafeDict) Len() int {
	d.RLock()
	defer d.RUnlock()
	return len(d.data)
}
 
func (d *SafeDict) Put(key string, value int) (int, bool) {
	d.Lock()
	defer d.Unlock()
	old_value, ok := d.data[key]
	d.data[key] = value
	return old_value, ok
}
 
func (d *SafeDict) Get(key string) (int, bool) {
	d.RLock()
	defer d.RUnlock()
	old_value, ok := d.data[key]
	return old_value, ok
}
 
func (d *SafeDict) Delete(key string) (int, bool) {
	d.Lock()
	defer d.Unlock()
	old_value, ok := d.data[key]
	if ok {
		delete(d.data, key)
	}
	return old_value, ok
}

        其中 SafeDict 类型的 map 就是线程安全的,包装前的普通 map 是非线程安全的。

        到此 Go 实现线程安全 map 读写(sync.RWMutex)介绍完成。

以上是关于Go Map 为啥是非线程安全的?的主要内容,如果未能解决你的问题,请参考以下文章

Java线程安全和非线程安全

为啥Servlet中的实例变量不是线程安全的[重复]

golang sync.Map 原理以及性能分析

转:golang实现线程安全的map

图解Go里面的sync.Map了解编程语言核心实现源码

Go语言 sync.Map(在并发中使用)