Go 语言中的 Sync.Map 详解:并发安全的 Map 实现

简介: `sync.Map` 是 Go 语言中用于并发安全操作的 Map 实现,适用于读多写少的场景。它通过两个底层 Map(`read` 和 `dirty`)实现读写分离,提供高效的读性能。主要方法包括 `Store`、`Load`、`Delete` 等。在大量写入时性能可能下降,需谨慎选择使用场景。

1. Sync.Map 的必要性

在 Go 语言中,标准的 map 类型并不是线程安全的。在多个 goroutine 并发访问时,需要使用锁来保护数据。为了解决这个问题,Go 语言在 1.9 版本中引入了 sync.Map,它是一个并发安全的 Map 实现,可以在多个 goroutine 中安全地读写数据。

为什么Map的并发是不安全的?

2. Sync.Map 的底层原理

sync.Map 底层使用了两个原生的 Map:一个是 read,用于读操作,另一个是 dirty,用于写操作。其中,read 可视为“高速缓存”,当 goroutine 从 sync.Map 中读数据时,会首先查看 read 这个缓存层是否有用户需要的数据。如果有,则通过原子操作将数据读取并返回,这是 sync.Map 的快路径,也是其读性能极高的原因。

写操作直接写入 dirty,而 读操作则先读 read,如果没有命中,则再读 dirty

image.png

3. 适用场景

sync.Map 适用于以下两种场景:

  • 写少读多:例如缓存,只写一次,读取多次。
  • 多个 goroutine 操作不同 key:多个 goroutine 读取、写入和覆盖不相交的 key 集的条目。

因为大量写入的时候,会导致read map读不到数据而进一步加锁读取,同时dirty map也会一直晋升为read map,整体性能差,不如map + mutex

4. Sync.Map 的方法

sync.Map 提供了以下几个方法:

  • Store(key, value any):向 Map 中存储键值对。
  • Load(key any):根据键获取值。
  • Delete(key any):删除键值对。
  • LoadAndDelete(key any):获取并删除键值对。
  • LoadOrStore(key, value any):如果 key 已经存在,返回对应值,如果不存在,存储键值对。
  • Range(f func(key, value any) bool):遍历 Map 中的键值对。

5.代码实现

image.png

总结

sync.Map 是 Go 语言中一个非常实用的并发安全的 Map 实现,特别适用于读多写少的场景。通过其底层的读写分离机制,sync.Map 提供了高效的读性能和简洁的使用方式。然而,在大量写入的情况下,由于需要频繁更新 read,可能会导致性能下降,因此需要根据实际场景选择使用。

相关文章
|
6月前
|
存储 人工智能 安全
深入理解 go sync.Map - 基本原理
本文介绍了 Go 语言中 `map` 在并发使用时的常见问题及其解决方案,重点对比了 `sync.Mutex`、`sync.RWMutex` 和 `sync.Map` 的性能差异及适用场景。文章指出,普通 `map` 不支持并发读写,容易引发错误;而 `sync.Map` 通过原子操作和优化设计,在某些场景下能显著提升性能。同时详细讲解了 `sync.Map` 的基本用法及其适合的应用环境,如读多写少或不同 goroutine 操作不同键的场景。
280 1
|
8月前
|
存储 安全 Go
Map的遍历与判断键是否存在-《Go语言实战指南》
本文介绍了 Go 语言中对 `map` 的常见操作,包括遍历所有项和判断键是否存在。通过 `for range` 可以遍历 `map` 的键值对、仅键或仅值(需忽略键)。注意,`map` 遍历顺序是随机的。判断键是否存在时,使用双赋值语法 `value, ok := map[key]`,其中 `ok` 表示键是否存在。直接访问不存在的键会返回类型的零值,可能导致逻辑错误。掌握这些机制可更安全高效地处理键值对数据。
|
存储 安全 Go
Go语言中的map数据结构是如何实现的?
Go 语言中的 `map` 是基于哈希表实现的键值对数据结构,支持快速查找、插入和删除操作。其原理涉及哈希函数、桶(Bucket)、动态扩容和哈希冲突处理等关键机制,平均时间复杂度为 O(1)。为了确保线程安全,Go 提供了 `sync.Map` 类型,通过分段锁实现并发访问的安全性。示例代码展示了如何使用自定义结构体和切片模拟 `map` 功能,以及如何使用 `sync.Map` 进行线程安全的操作。
386 9
|
3月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
264 1
|
11月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
11月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
5月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
356 1
|
5月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
447 0
|
5月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
301 0
|
5月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
306 0