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"的错误。
相关推荐
HZ·湘怡1 小时前
二叉树 2 堆
算法
wabs6668 小时前
关于贪心算法的思考
算法·贪心算法
社交怪人8 小时前
【判断大小】信息学奥赛一本通C语言解法(题号1043)
算法
Snasph9 小时前
GNU Make 用户手册(中文版)
服务器·算法·gnu
深圳市机智人激光雷达9 小时前
技术筑牢安全冗余:激光雷达在自动驾驶高阶感知中的底层价值与范式演进
人工智能·安全·机器学习·3d·机器人·自动驾驶·无人机
江澎涌9 小时前
拆解与 AI 的一次对话
人工智能·算法·程序员
TechWayfarer9 小时前
IP风险等级评估接入实战:金融信贷如何用IP画像辅助风控审核
python·tcp/ip·安全·金融
sheeta19989 小时前
LeetCode 每日一题笔记 日期:2026.06.02 题目:3635. 最早完成陆地和水上游乐设施的时间 II
笔记·算法·leetcode
Lsk_Smion10 小时前
力扣实训 _ [102].层序遍历--前序--后续_递归与非递归的实现
数据结构·算法·leetcode
ylscode10 小时前
Comodo防火墙曝致命零日漏洞:单个IPv6数据包即可触发Windows蓝屏死机
运维·网络·windows·安全·安全威胁分析