

新闻资讯
技术学院sync.Map 不适合作为通用缓存,因其无过期机制、无容量限制、遍历无序且缺乏原子的“读+过期检查+删除”操作;推荐使用 go-cache,它轻量、线程安全、支持 TTL 和定时清理。
sync.Map 直接当缓存用很多人一想“内存缓存”,立刻写 sync.Map 存键值,但实际会踩坑:sync.Map 没有过期机制、不支持容量限制、遍历时无法保证顺序,更关键的是——它不提供原子的“读+过期检查+删除”组合操作。真实缓存需要 Get 时自动剔除过期项,否则缓存会持续膨胀、返回脏数据。
github.com/patrickmn/go-cache 快速落地这个库轻量(单文件)、线程安全、支持 TTL 和清理策略,比自己手撸更可靠。注意它不是 LRU,而是基于定时器 + 延迟删除(lazy eviction),适合中小规模高频读、低频写的场景。
go get github.com/patrickmn/go-cache
cache := cache.New(5*time.Minute, 10*time.Minute)(第一个参数是 item 默认 TTL,第二个是清理 goroutine 执行间隔)
cache.Set("user:123", userObj, cache.D
efaultExpiration) 或 cache.Set("token:abc", "xxx", 30*time.Second)
if x, found := cache.Get("key"); found { ... },found == false 不代表 key 不存在,可能是已过期被逻辑删除(还没被清理 goroutine 物理清除)如果真要自己写(比如规避依赖、或需要精确 LRU 行为),别直接套用 container/list + map 教程代码——它们通常忽略并发和内存泄漏风险。
map 的 key 类型必须可比较(不能是 slice、map、func),常见错误是用 []byte 当 key,得转成 string 或用 unsafe.String 避免拷贝list 中移除节点,再 PushFront,中间不能被其他 goroutine 插入导致 panic;必须用 sync.RWMutex 或 sync.Mutex 锁住整个操作序列list 节点,一定要同步从 map 中 delete,否则 map 持有指针造成内存泄漏光跑通 Set/Get 不够,重点验证边界行为:
Get 返回 nil, false(不是 nil, true)go-cache 内部用 sync.RWMutex,自己写的必须测)runtime.ReadMemStats 对比前后 Alloc 字段)100* time.Millisecond),用 time.Sleep 后再 Get,确认命中率为 0真正难调的不是存取逻辑,是过期时机和清理节奏的配合——尤其在高并发下,清理 goroutine 可能滞后,导致短暂返回过期值。生产环境建议加一层包装,Get 时手动检查时间戳再决定是否返回。