使用sync.RWMutex保护map或sync.Map实现并发安全缓存,结合TTL和定期清理机制,兼顾性能与一致性。

在Golang中实现并发安全的缓存,核心是确保多个goroutine同时读写时数据的一致性和性能。直接使用map配合sync.RWMutex是最常见且有效的方式,也可以借助sync.Map简化部分场景。
使用 sync.RWMutex 保护普通 map
大多数情况下,推荐使用sync.RWMutex来保护一个普通的map。读操作频繁时,读锁允许多个goroutine同时访问,写锁则独占,兼顾性能与控制。
示例:
type Cache struct {
data map[string]interface{}
mu sync.RWMutex
}
func NewCache() *Cache {
return &Cache{
data: make(map[string]interface{}),
}
}
func (c *Cache) Get(key string) (interface{}, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
val, exists := c.data[key]
return val, exists
}
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)
}
这种方式清晰、可控,适合需要自定义过期机制、淘汰策略等扩展功能的场景。
立即学习“go语言免费学习笔记(深入)”;
使用 sync.Map(适用于简单场景)
sync.Map是Go为高并发读写设计的专用并发安全map,适用于读多写少或键集不断变化的场景。它自带原子操作,无需额外锁。
示例:
var cache sync.Map
// 写入
cache.Store("key", "value")
// 读取
if val, ok := cache.Load("key"); ok {
fmt.Println(val)
}
// 删除
cache.Delete("key")
注意:sync.Map不支持遍历删除或复杂操作,且一旦使用,应全程使用其方法,不能混合普通map操作。
添加过期时间(TTL)支持
真实缓存通常需要自动过期能力。可以在value中封装一个带过期时间的结构体,并启动清理协程定期扫描。
关键点:
- 每个value记录过期时间(如
time.Time) - Get时判断是否过期,过期则返回不存在
- 可选:后台goroutine定期清理过期项
示例片段:
type item struct {
value interface{}
expireTime time.Time
}
func (i *item) isExpired() bool {
return time.Now().After(i.expireTime)
}
在Get中加入判断:
func (c *Cache) Get(key string) (interface{}, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
item, exists := c.data[key]
if !exists || item.isExpired() {
return nil, false
}
return item.value, true
}
基本上就这些。根据场景选择sync.RWMutex + map还是sync.Map,再按需加上TTL和清理机制,就能构建出高效又安全的并发缓存。不复杂但容易忽略细节,比如过期检查的时机和锁粒度。










