go中普通map和sync.map的区别小结

Written by

in

文章目录
  • Go 内置的 map 是非并发安全的: 在单协程里读写没问题; 多协程同时写会触发 fatal error: concurrent map writes; 多协程并发读写需要自己加锁(如 sync.RWMutex)。 源码层面(runtime/map.go): map 内部通过 hmap 结构体存储桶(buckets)管理数据; 设计目标是高性能单线程; 并没有加锁逻辑。
  • Go 在 1.9+ 引入了 sync.Map,为高并发场景做了专门优化。特点: 并发安全,内部已经封装了锁; 针对读多写少的场景做了特别优化(类似“读写分离”)。 源码层面(sync/map.go): type Map struct { mu Mutex // 写操作用的锁 read atomic.Value // 存储只读部分,原子读 dirty map[any]*entry // 可写部分,写时更新 misses int // 记录从 read 读取失败的次数 } 核心机制: 双 map 设计: read(只读,atomic.Value):无锁读,性能高; dirty(写缓冲,受锁保护):存储新增/修改的数据; 写时迁移策略:当 read 中 miss 次数过多,会把 dirty 提升为 read; 保证读快写慢的同时,整体高并发安全。 通过read和dirty分别存储读写状态,以空间换时间的策略,去减少锁冲突。
  • // 普通 map + 锁 var m = make(map[string]int) var mu sync.RWMutex func safeWrite(k string, v int) { mu.Lock() defer mu.Unlock() m[k] = v } func safeRead(k string) (int, bool) { mu.RLock() defer mu.RUnlock() v, ok := m[k] return v, ok } 和 sync.Map 相比: 普通 map+RWMutex:写性能更好,适合频繁写; sync.Map:读性能更好,适合读多写少。
  • 普通 map 是非并发安全的,需要开发者手动用 sync.RWMutex 保证线程安全。sync.Map 内部采用 读写分离(read + dirty) 的双 map 设计,读操作可以无锁原子读,写操作用锁保护,并在一定 miss 次数后把 dirty 提升为 read。适用场景不同: sync.Map:读多写少,典型场景如缓存、配置表; map+RWMutex:写多的场景更优。 到此这篇关于go中普通map和sync.map的区别小结的文章就介绍到这了,更多相关go中普通map和sync.map内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: golang中使用sync.Map的方法 深度解密 Go 语言中的 sync.map Go 并发读写 sync.map 详细 Go语言sync.Map详解及使用场景 Golang中的同步工具sync.Map示例详解 Golang sync.Map原理深入分析讲解 Golang sync.Map底层实现场景示例详解 Golang map与sync.map的异同详解 一文带你深入探究Go语言中的sync.Map golang读写分离sync.Map的使用 go sync.Map基本原理深入解析
  • 目录
    • 1. 普通map的特点
    • 2.sync.Map的特点
    • 3. 举个对比例子
    • 4. 面试回答

    Go 内置的 map非并发安全的:

    • 单协程里读写没问题;
    • 多协程同时写会触发 fatal error: concurrent map writes
    • 多协程并发读写需要自己加锁(如 sync.RWMutex)。

    源码层面(runtime/map.go):

    • map 内部通过 hmap 结构体存储桶(buckets)管理数据;
    • 设计目标是高性能单线程
    • 并没有加锁逻辑。

    Go 在 1.9+ 引入了 sync.Map,为高并发场景做了专门优化。
    特点:

    • 并发安全,内部已经封装了锁;
    • 针对读多写少的场景做了特别优化(类似“读写分离”)。

    源码层面(sync/map.go):

    type Map struct {
        mu Mutex               // 写操作用的锁
        read atomic.Value      // 存储只读部分,原子读
        dirty map[any]*entry   // 可写部分,写时更新
        misses int             // 记录从 read 读取失败的次数
    }
    

    核心机制:

    • 双 map 设计

      • read(只读,atomic.Value):无锁读,性能高;
      • dirty(写缓冲,受锁保护):存储新增/修改的数据;
    • 写时迁移策略:当 read 中 miss 次数过多,会把 dirty 提升为 read

    • 保证读快写慢的同时,整体高并发安全。

    通过readdirty分别存储读写状态,以空间换时间的策略,去减少锁冲突。

    // 普通 map + 锁
    var m = make(map[string]int)
    var mu sync.RWMutex
    
    func safeWrite(k string, v int) {
        mu.Lock()
        defer mu.Unlock()
        m[k] = v
    }
    
    func safeRead(k string) (int, bool) {
        mu.RLock()
        defer mu.RUnlock()
        v, ok := m[k]
        return v, ok
    }
    

    sync.Map 相比:

    • 普通 map+RWMutex写性能更好,适合频繁写
    • sync.Map读性能更好,适合读多写少

    普通 map 是非并发安全的,需要开发者手动用 sync.RWMutex 保证线程安全。
    sync.Map 内部采用 读写分离(read + dirty) 的双 map 设计,读操作可以无锁原子读,写操作用锁保护,并在一定 miss 次数后把 dirty 提升为 read
    适用场景不同:

    • sync.Map:读多写少,典型场景如缓存、配置表;
    • map+RWMutex:写多的场景更优。

    到此这篇关于go中普通map和sync.map的区别小结的文章就介绍到这了,更多相关go中普通map和sync.map内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • golang中使用sync.Map的方法
    • 深度解密 Go 语言中的 sync.map
    • Go 并发读写 sync.map 详细
    • Go语言sync.Map详解及使用场景
    • Golang中的同步工具sync.Map示例详解
    • Golang sync.Map原理深入分析讲解
    • Golang sync.Map底层实现场景示例详解
    • Golang map与sync.map的异同详解
    • 一文带你深入探究Go语言中的sync.Map
    • golang读写分离sync.Map的使用
    • go sync.Map基本原理深入解析

    站内搜索