sync.map 不支持过期机制,因其缺乏原子性遍历删除操作,手动实现易致竞态、内存泄漏或误删;推荐用 struct 包裹值与过期时间,由调用方读取时校验并决定是否使用。
sync.Map 本身不支持过期机制,硬加会导致数据残留、内存泄漏或并发误删——别直接往里塞 time.Now() 和判断逻辑。
为什么不能直接用 sync.Map 存带过期时间的值
因为 sync.Map 没有遍历 + 条件删除的原子操作,你无法安全地在读写同时清理过期项;手动启 goroutine 定时扫描会引发竞态(Load/Delete 非原子配对),且扫描本身开销随数据量线性增长。
- 调用
Range时无法在回调中调用Delete(文档明确禁止) - 用
LoadAndDelete前必须先Load判断是否过期,但两次操作之间可能被其他 goroutine 修改 - 过期检查逻辑若放在
Load后做,返回值已不可信(刚查没过期,返回途中就过期了)
推荐做法:用 sync.Map 存原始值,过期交给外部控制
把过期逻辑从缓存层剥离,让业务决定“要不要用这个值”,而不是让缓存决定“该不该留它”。典型组合是:sync.Map + time.Time 字段 + 调用方主动校验。
- 存入时:用 struct 包裹值和
expireAt,例如struct{ v interface{}; expireAt time.Time } - 读取时:先
Load,再立刻检查expireAt.After(time.Now()),不满足则视作未命中 - 写入时:避免覆盖正在使用的旧值,可配合
LoadOrStore或先Load再条件Store
示例片段: