Golang|并行读写map和slice

发布于:2025-04-16 ⋅ 阅读:(32) ⋅ 点赞:(0)

并行读写map

在这里插入图片描述

  • 这段代码存在并发读写map的问题,即使操作的key不同,也会导致数据竞争。
  • map的并发不安全特性:Go语言原生的map不支持并发读写操作。即使对不同key进行操作,底层数据结构仍可能发生修改(如rehash),这会引发panic。
  • 两个goroutine同时对同一个map进行读写操作,触发 fatal error: concurrent map read and map write
  • map的元数据(如桶数量、扩容状态、哈希种子等)是全局的。例如:1、当写入操作触发扩容(rehash)时,整个哈希表会重新分配桶并迁移数据。此时,即使操作的是不同的key,所有读写操作都可能访问到正在变化的元数据或桶结构,导致不一致。2、扩容过程中,旧桶和新桶的状态可能同时被修改,其他协程若并发访问,可能读取到中间状态的数据。

在这里插入图片描述

  • 并行读map是允许的

在这里插入图片描述

  • 并行写map是不允许的,会导致脏数据,fatal error: concurrent map writes

  • 既然不允许并行,那就用锁的形式,把读写串行起来!

在这里插入图片描述
在这里插入图片描述


  • golang中 sync.Map{} 本身就是支持发读写的。
  • 在Go语言中,sync.Map 是标准库 sync 包提供的一个并发安全的键值对映射结构。它专为高并发场景设计,避免了传统 map 结合互斥锁(如 sync.Mutex)时的锁竞争问题。
  • 直接声明 var m sync.Map 即可使用,无需显式初始化。
  • Store(key, value): 存储键值对。
  • Load(key): 读取键对应的值,返回 (value, bool)。
  • LoadOrStore(key, value): 若键存在则返回现有值,否则存储并返回给定值。
  • Delete(key): 删除键。
  • Range(func(key, value) bool): 遍历所有键值对,遍历时可通过返回 false 提前终止。

在这里插入图片描述

  • 但是有些情况下用sync.Map来计数也会出现问题
  • 高并发下的两个协程同时执行同一段代码,会出现脏写问题

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

并行读写slice

  • 切片支持并发读写,至少说,不会报 fatal error
  • 但是slice并不保证并发读写后的正确性

在这里插入图片描述
在这里插入图片描述

  • 代码运行起来后会发现实际输出的结果远远小于我们的预期,因为在高并发的场景下会有很多操作重复了,在原始的数据在去执行加1操作,导致脏数据的产生
  • 如果确实要并发处理slice,最好是事先约定好每个协程负责处理slice的一个部分,且各个协程负责的部分不要有交集!!!

在这里插入图片描述