Go中实现并发安全缓存需用sync.RWMutex配map,读用RLock允许多个goroutine并发,写用Lock保证独占;基础结构含mu和data,Get/Set/Delete方法分别加读锁、写锁;高并发可分片优化锁粒度。

在 Go 中实现并发安全的缓存,核心是避免多个 goroutine 同时读写共享 map 导致 panic(如 fatal error: concurrent map writes)或数据不一致。直接使用原生 map 不是线程安全的,必须配合同步机制。最常用、轻量且可控的方式是用 sync.RWMutex 配合 map —— 读多写少场景下性能优于全互斥锁。
为什么选 RWMutex 而不是 Mutex
sync.RWMutex 区分读锁(RLock)和写锁(Lock),允许多个 goroutine 同时读,但写操作会独占锁。对缓存这种「读远多于写」的典型场景,能显著提升并发吞吐。而纯 sync.Mutex 会让所有读操作排队,成为瓶颈。
基础结构体设计
定义一个带锁的缓存结构,封装 map 和读写锁:
type Cache struct {
mu sync.RWMutex
data map[string]interface{}
}
func NewCache() *Cache {
return &Cache{
data: make(map[string]interface{}),
}
}
立即学习“go语言免费学习笔记(深入)”;
关键方法实现(读/写/删除)
所有访问 data 的方法都必须加锁,且严格区分读写场景:
-
Get(读):用
RUnlock()+RLock(),允许并发读 -
Set(写):用
Lock()+Unlock(),确保写独占 - Delete(写):同 Set,需写锁
-
注意 nil 检查:在 Get 中判断 key 是否存在,避免返回零值造成歧义(例如想缓存
nil或false)
func (c *Cache) Get(key string) (value interface{}, ok bool) {
c.mu.RLock()
defer c.mu.RUnlock()
value, ok = c.data[key]
return
}
func (c *Cache) Set(key string, value interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = value
}
func (c *Cache) Delete(key string) {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.data, key)
}
进阶考虑:避免锁粒度太粗
如果缓存条目极多、更新频繁,单把大锁可能成为瓶颈。可考虑分片(sharding):将 map 拆成多个子 map,每个配独立 RWMutex。例如按 key 哈希取模选择分片,降低锁冲突概率。标准库 sync.Map 就是类似思路的优化实现(但适用于更简单场景,不支持遍历或自定义过期)。










