golang的map是不是并发安全的?怎么保证安全?

参考链接
https://www.iamshuaidi.com/23354.html

map 并不是并发安全的

map是引用类型,如果两个map同时指向一个底层,那么一个map的变动会影响到另一个map。 map 的并发不安全主要是因为缺乏内置的锁机制和原子操作,并且在扩容过程中可能会导致数据不一致。

  • 无锁机制: map 的底层数据结构是一个哈希表,当多个 Goroutine 并发地对 map 进行读写操作时,可能会导致数据竞争(DataRace)。因为 map 没有内置的锁机制来保护并发访问,所以在并发读写时可能会造成数据不一致或损坏。

  • 非原子操作: 尽管 map 的操作看起来是单个的语句,比如 mkey = value 和 delete(m,key),但实际上它们都不是原子操作。在并发环境中,一个 map 操作可能会由多个机器指令组成,而且在执行期间可能会被中断或切换到另一个Goroutine,这就增加了出错的可能性。

  • 扩容操作【重点】: 当 map 的元素个数超过了当前容量的时候,Go 语言会自动扩容map,这时会重新分配内存,并将原有的键值对重新哈希到新的内存位置。在扩容过程中,如果有其他 Goroutine并发地进行读写操作,可能会导致指针失效、丢失数据或者死锁等问题。

因此,这意味着在多个 Goroutine 同时读取和写入 map 时可能会导致竞态条件(Race Condition)和数据竞争(Data Race)。当多个 Goroutine 并发地读取和写入同一个 map 时,可能会出现不可预期的结果,甚至导致程序崩溃。

要保证 map 的并发安全,可以采取以下几种方式:

使用互斥锁(Mutex)

使用读写互斥锁(RWMutex)

使用并发安全的数据结构:sync.Map

1. 使用互斥锁(Mutex)

可以在读取和写入 map 的操作上加锁,保证同一时刻只有一个 Goroutine 能够访问 map。通过 sync.Mutex 提供的锁机制可以很容易地实现这一点。

go 复制代码
import "sync"

var mu sync.Mutex
var m = make(map[string]int)

// 写操作
mu.Lock()
m["key"] = value
mu.Unlock()

// 读操作
mu.Lock()
value := m["key"]
mu.Unlock()

2. 使用读写互斥锁(RWMutex):

如果多个 Goroutine 需要同时读取 map,但只有一个 Goroutine 写入 map,可以使用 sync.RWMutex 提供的读写锁机制。这种方式可以提高并发读取的效率。

go 复制代码
import "sync"

var mu sync.RWMutex
var m = make(map[string]int)

// 写操作
mu.Lock()
m["key"] = value
mu.Unlock()

// 读操作
mu.RLock()
value := m["key"]
mu.RUnlock()

3. 使用并发安全的数据结构:

在 Go 语言的 sync 包中还提供了一些并发安全的数据结构,例如 sync.Map。使用 sync.Map 可以避免手动管理锁,简化并发编程。

go 复制代码
import "sync"

var m sync.Map

// 写操作
m.Store("key", value)

// 读操作
value, ok := m.Load("key")

总的来说,要保证 map 的并发安全,需要在并发访问时进行适当的同步控制,使用锁机制或并发安全的数据结构来保护 map 的读写操作。

===========================

额外知识:

  1. map是引用类型,如果两个map同时指向一个底层,那么一个map的变动会影响到另一个map。
  2. map的零值(Zero Value)是nil,对nil map进行任何添加元素的操作都会触发运行时错误(panic)。因此,使用前必须先创建map,使用make函数,例如:m := make(mapstringint)。
  3. map的键可以是任何可以用 == 或!=操作符比较的类型,如字符串,整数,浮点数,复数,布尔等。但是,slice,map,和function类型不可以作为map的键,因为这些类型不能使用==或!=操作符进行比较。
  4. map在使用过程中不保证遍历顺序,即:map的遍历结果顺序可能会不一样,所以在需要顺序的场合,要自行处理数据并排序。
  5. map进行的所有操作,包括读取,写入,删除,都是不安全的。也就是说,如果你在一个goroutine中修改map,同时在另一个goroutine中读取map,可能会触发"concurrent map read and map write"的错误。
相关推荐
CHANG_THE_WORLD5 分钟前
深入理解递归:从函数调用到调用栈的完整执行过程
java·开发语言·算法
liukuang11017 分钟前
Zara“夺命裤”风波,白晨铭的安全大考
安全
microrain35 分钟前
从硬编码到热插拔:SagooIoT插件架构如何打破物联网平台的扩展瓶颈
物联网·golang·开源·sagooiot
Android小码家1 小时前
OWASP 移动应用安全之授权(MASTG-DEMO-0090)
android·安全·frida
Multipath7121 小时前
智能巡检机器人多链路聚合路由解决方案
网络·5g·安全·实时音视频·信息与通信
学习溢出1 小时前
【网络安全】Living off the Land 攻击 | 蓝队防守
安全·web安全·网络安全
上海云盾-小余1 小时前
全链路多层防护体系,一站式拦截 DDoS、CC、爬虫与注入攻击
网络·爬虫·安全·ddos
geovindu2 小时前
go:Backtracking Algorithm
开发语言·后端·算法·golang·回溯算法
潘潘的嵌入式日记2 小时前
一个宏在调试阶段挡住所有误操作
安全·嵌入式··调试·编译期·bring-up
qq_452396232 小时前
第六篇:《并发编程核心:Goroutine 与 Channel》
golang