You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于Go语言RWMutex(读写互斥锁)使用的困惑求助

搞定Go中RWMutex的正确打开方式,实现你的读写控制需求

兄弟,我太懂你这种困惑了!Go的RWMutex看似简单,但实际用起来很容易踩锁的逻辑坑,尤其是读锁和写锁的互斥规则没搞清楚的时候。先给你理清楚核心逻辑,再给你一个能完美实现你需求的示例代码。

先搞懂RWMutex的核心规则

这三点是你必须记牢的:

  • 写锁是完全排他的:只要有一个goroutine拿到了Lock()(写锁),其他所有goroutine不管是想拿读锁RLock()还是写锁Lock(),都会被阻塞,直到写锁被Unlock()释放。
  • 读锁是共享的:多个goroutine可以同时持有RLock()(读锁),并行执行读操作,互不干扰。但如果此时有goroutine想拿写锁,它会被阻塞,直到所有读锁都被RUnlock()释放。
  • 你的问题根源:大概率是读操作没加读锁!这样就算写锁生效了,读操作还是直接裸访问map,根本没被锁住;如果错误地给读操作加了写锁,那读操作就变成串行的了,自然“反而更糟”。

实现你需求的正确代码示例

下面是一个封装好的安全Map,完全符合你“读操作并行,写操作时所有读都被锁住”的要求:

import "sync"

// SafeMap 带读写锁的安全Map
type SafeMap struct {
    mu   sync.RWMutex
    data map[string]int // 这里可以替换成你实际需要的结构体类型,比如包含age字段的结构
}

// NewSafeMap 创建一个初始化好的SafeMap
func NewSafeMap() *SafeMap {
    return &SafeMap{
        data: make(map[string]int),
    }
}

// Get 读操作:使用读锁,支持多goroutine并行读取
func (m *SafeMap) Get(key string) (int, bool) {
    m.mu.RLock()         // 加读锁
    defer m.mu.RUnlock() // 用defer确保锁一定会被释放,避免死锁
    val, ok := m.data[key]
    return val, ok
}

// Set 写操作:使用写锁,排他性,此时所有读/写操作都会被阻塞
func (m *SafeMap) Set(key string, val int) {
    m.mu.Lock()         // 加写锁
    defer m.mu.Unlock() // 确保锁释放
    m.data[key] = val
}

代码逻辑解释

  • 当多个goroutine同时调用Get()时,它们会各自拿到读锁,并行执行读操作,效率拉满。
  • 当某个goroutine调用Set()时,它会先抢占到写锁,此时所有后续的Get()和Set()都会进入阻塞状态,直到Set()执行完毕并释放写锁,完美实现“写时所有读加锁”的需求。

避坑提醒

  • 所有读操作必须加读锁:哪怕你觉得读操作是“只读”的,也必须加RLock(),否则会出现数据竞争,写操作的锁根本管不住裸读的goroutine。
  • 不要滥用写锁:读操作就用读锁,写操作才用写锁,不然完全浪费了RWMutex支持并行读的优势。
  • 用defer释放锁:这是最稳妥的方式,避免因为代码分支或者panic导致锁没释放,进而引发死锁。

内容的提问来源于stack exchange,提问作者Francesco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:06:37