在 Go 中减少锁竞争的核心是避免多 goroutine 长时间争抢同一互斥锁:优先用 atomic 处理单字段简单操作;对多字段一致性用细粒度 Mutex;读多写少用 RWMutex;高频 map 用分段锁;耗时操作移出锁外;必要时采用 sync.Pool、channel 或 sync.Map 等无锁或轻量方案。
在 Go 中减少锁竞争,核心思路是避免让多个 goroutine 长时间争抢同一把互斥锁。细粒度锁和原子操作不是互斥选项,而是互补手段:对简单、无副作用的共享状态(如计数器、标志位),优先用 sync/atomic;对需要保护多字段一致性或复杂逻辑的结构,才引入 sync.Mutex,并尽量缩小其保护范围。
当只读写单个基础类型(int32、int64、uint32、bool、指针等)且无需与其他字段联动时,原子操作开销远低于加锁,且完全无竞争阻塞。
atomic.AddInt
64(&counter, 1) 替代 mu.Lock(); counter++; mu.Unlock()
atomic.LoadInt64(&counter) 和 atomic.StoreInt64(&counter, v) 替代带锁读写atomic.CompareAndSwapInt64(&flag, 0, 1) 实现一次性初始化或状态翻转,避免重复执行不要用一把全局锁保护整个 map 或大结构体。根据实际并发访问路径,将锁粒度下沉到更小的逻辑单元。
sync.RWMutex,读写仅锁定对应桶当读操作远多于写操作时,sync.RWMutex 允许多个 goroutine 同时读,仅写操作互斥,显著提升吞吐。
RLock()/RUnlock(),写操作仍用 Lock()/Unlock()
RWMutex 不是银弹——写操作会阻塞后续所有读,若写较频繁,可能反而加剧饥饿;此时需结合缓存或批量更新缓解对极致性能要求场景,可探索更轻量或更安全的替代方案。
sync.Pool 复用临时对象,减少 GC 压力间接降低锁争用(如日志缓冲区、序列化器实例)sync.Map(适用于读多写少且 key 动态变化的 map),但注意它不保证迭代一致性,也不适合强一致性场景