为什么sync.Map可以做到线程安全

举报
码乐 发表于 2025/08/03 07:12:01 2025/08/03
【摘要】 1 简介为什么 sync.Map 是线程安全的?sync.Map 是 Go 标准库中专为并发访问设计的映射结构。它在内部通过以下机制实现线程安全: 2 sync.Map是安全的线程同步sync.Map 被认为是线程同步安全的,因为它提供了一种用于安全高效的 并发读写的内置机制。它结合使用 原子作、锁和数据结构来确保 其内容保持一致 且可访问 ,即使有多个 goroutine 正在同时修改m...

1 简介

为什么 sync.Map 是线程安全的?

sync.Map 是 Go 标准库中专为并发访问设计的映射结构。它在内部通过以下机制实现线程安全:

2 sync.Map是安全的线程同步

sync.Map 被认为是线程同步安全的,因为它提供了一种用于安全高效的 并发读写的内置机制。

它结合使用 原子作、锁和数据结构来确保 其内容保持一致 且可访问 ,即使有多个 goroutine 正在同时修改map。

这使得 它适合在高并发环境中使用, 其中多个 goroutine 同时访问和修改共享数据。

✅ 1. 内部读写分离结构(dual-map 技术)

  sync.Map 内部使用了两个 map:

  read map(只读):用于高效并发读取;

  dirty map(写 map):当发生写操作或 miss 时使用,并通过标志 misses 控制是否同步合并到 read map。

✅ 2. CAS + 互斥锁混合机制

多数 读操作 是 lock-free(无锁)的,极大提高了性能;

当遇到 key miss 或写操作时,才使用 互斥锁(sync.Mutex) 保证写入安全;

通过“懒同步”机制延迟写入合并,降低锁竞争。

✅ 3. 避免 GC 扫描

sync.Map 避免频繁修改底层结构,因此减少了 map resizing 和 GC 扫描压力。

3 map + sync.Mutex 与 sync.Map 有何不同

特性			sync.Map									map + sync.Mutex
并发读写安全	✅ 内建支持							✅ 需手动加锁
写性能			高并发下较优秀(写少读多场景)					写多时锁粒度较粗,性能较差
读性能			无锁读性能极高(共享 read map)			每次读都需加锁
内存占用		略高,存在 read/dirty map 和 miss 			计数器	更低,结构更简单
使用复杂度		简单,直接调用 Load, Store, Delete, Range 等方法		需手动封装锁逻辑
适用场景	多读少写、高并发读;缓存场景				写多读少、自定义控制并发行为

3 示例

🔹 1. 使用 sync.Map

      var m sync.Map

      // 写入
      m.Store("a", 1)

      // 读取
      value, ok := m.Load("a")

      // 删除
      m.Delete("a")

      // 遍历
      m.Range(func(k, v any) bool {
          fmt.Println(k, v)
          return true
      })

🔸 2. 使用 map + sync.RWMutex

    type SafeMap struct {
        mu sync.RWMutex
        m  map[string]int
    }

    func (s *SafeMap) Set(k string, v int) {
        s.mu.Lock()
        defer s.mu.Unlock()
        s.m[k] = v
    }

    func (s *SafeMap) Get(k string) (int, bool) {
        s.mu.RLock()
        defer s.mu.RUnlock()
        val, ok := s.m[k]
        return val, ok
    }

    func (s *SafeMap) Delete(k string) {
        s.mu.Lock()
        defer s.mu.Unlock()
        delete(s.m, k)
    }

4 小结建议

 场景										推荐使用方式
多读少写(如缓存、配置、黑名单)		✅ 使用 sync.Map
写多读少,或对锁粒度有精细控制要求		✅ 使用 map + sync.RWMutex
需要迭代时稳定快照						✅ 手动加锁的普通 map

读写均匀但性能非常关键 ,考虑使用第三方高性能并发 map(如分片 map)sync.Map是 Go 开发人员武器库中的一个强大工具,但它不是灵丹妙药。它的内部结构针对某些用例进行了优化,特别是当读取作较多而写入相对较少时。

在频繁写入或竞争 goroutine 数量较少的情况下,与常规map配合可以更有效。

【版权声明】本文为华为云社区用户翻译文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容, 举报邮箱:cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。