sync.Map的实现原理

打印 上一主题 下一主题

主题 873|帖子 873|积分 2619

在 Go 语言中,sync.Map 是一个并发安全的映射结构,专门用于在高并发场景下处理键值对数据。它的并发安全是通过内部实现机制来包管的,而不是依赖外部的锁机制(如 sync.Mutex 或 sync.RWMutex)来手动掩护操纵。
sync.Map 并发安全的实现原理

sync.Map 采用了一种更复杂的数据结构和操纵策略来实现并发安全。它的核心设计可以分为以下几个方面:
1. 读写分离机制

sync.Map 的内部结构是通过读写分离实现的,主要由两个部分构成:

  • 只读部分(read map):用于存储稳定的数据。读取操纵主要从这个只读部分举行,制止锁的使用。
  • 脏数据部分(dirty map):当数据发生修改(写入、删除)时,会被移动到脏数据地区,写入的同时加锁来确保并发安全。
2. 快速读取路径


  • 无锁读取:如果数据已经存在于 read map 中(即稳定的数据),读取操纵不需要加锁,这使得 sync.Map 的读操纵非常高效。
  • 写时复制:当数据在 read map 中不存在时,可能存在于 dirty map 中。此时需要升级锁并从 dirty map 读取或写入数据。
3. 写入时的锁掩护


  • 当需要写入(Store 或 Delete)时,sync.Map 会在 dirty map 中举行操纵。写操纵会加锁,以确保并发写入时的安全性。
  • 每次写入时,sync.Map 都会检查 read map 和 dirty map 之间的数据是否需要同步(好比数据量超过某个阈值时),并对脏数据部分举行整理和迁徙。
4. 懒惰同步(Lazy Synchronization)

当读操纵频繁时,sync.Map 会把部分脏数据渐渐迁徙到 read map,从而减少读操纵对锁的依赖。这种延长同步策略包管了读操纵可以只管制止锁竞争,从而提升读取性能。
5. 原子操纵

sync.Map 的部分操纵(如 LoadOrStore、LoadAndDelete 等)采用了原子操纵。它们的实现使用了底层的原子性检查和赋值操纵,确保这些操纵能够在并发环境中保持一致性。
关键操纵说明


  • 读操纵 (Load)

    • 首先从 read map 中读取,如果找到,直接返回。
    • 如果在 read map 中没有找到,则会尝试从 dirty map 中读取,同时可能会触发一次锁定操纵。

  • 写操纵 (Store)

    • 写操纵会锁定 sync.Map,以包管在并发环境下对 dirty map 的安全写入。
    • 如果脏数据变多或写入频繁,可能会触发 read map 的同步,将一些脏数据迁徙到 read map。

  • 删除操纵 (Delete)

    • 删除操纵也会加锁,并删除 dirty map 中的数据。

  • 批量操纵 (Range)

    • Range 操纵遍历 sync.Map 中的所有数据,确保在遍历期间不会发生并发冲突。

代码示例
  1. package main
  2. import (
  3.     "fmt"
  4.     "sync"
  5. )
  6. func main() {
  7.     var m sync.Map
  8.     // 写入数据
  9.     m.Store("foo", 42)
  10.     m.Store("bar", 100)
  11.     // 读取数据
  12.     value, ok := m.Load("foo")
  13.     if ok {
  14.         fmt.Println("foo:", value)
  15.     }
  16.     // 删除数据
  17.     m.Delete("foo")
  18.     // 使用 Range 遍历所有元素
  19.     m.Range(func(key, value interface{}) bool {
  20.         fmt.Println(key, value)
  21.         return true
  22.     })
  23. }
复制代码
sync.Map 的优点


  • 读性能高:在读多写少的场景下表现非常优秀,因为 read map 读取时不需要加锁,减少了锁竞争。
  • 主动并发控制:sync.Map 不需要手动管理锁机制,减少了编写并发安全代码的复杂度。
  • 适合高并发场景:特殊是在大量读取的环境下,sync.Map 的性能优于传统的 map + sync.RWMutex 的方案。
何时使用 sync.Map


  • 读多写少的场景:当并发访问主要是读操纵,写操纵较少时,sync.Map 的读写分离机制使得它具有很高的性能。
  • 需要简单并发访问:当需要并发访问 map,而且不想手动管理锁时,sync.Map 是一个非常方便的工具。
何时不使用 sync.Map


  • 写操纵非常频繁:sync.Map 在写操纵上需要加锁,如果写操纵占比很高,可能不如手动加锁的传统 map 方案效率高。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

九天猎人

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表