← 中文资源

简体中文版本

带 TTL 过期的 Go LRU 缓存

用 map 加 container/list 实现线程安全的 LRU,读取时检查过期时间,写入时更新最近使用顺序并按容量淘汰最旧条目。

阅读英文原文

功能说明

示例用 map 保存键到链表元素的映射,用 container/list 维护最近使用顺序:每次命中把元素移到队首,写入超过容量时从队尾淘汰。每个条目还记录过期时间,Get 发现过期会先删除再按未命中处理。所有操作由互斥锁保护,统计命中、未命中和淘汰次数。

关键代码

item := element.Value.(*entry[K, V])
if !c.now().Before(item.expiresAt) {
	c.removeElement(element)
	c.stats.Misses++
	var zero V
	return zero, false
}
c.order.MoveToFront(element)

!now.Before(expiresAt) 表示“到达或超过过期时间”,避免边界上多存活一个时钟刻度。

使用注意

  • 过期条目只在被访问或容量淘汰时清理,没有后台清扫 goroutine,长期不访问的键会占内存。
  • Put 已存在的键会刷新值和过期时间,并把它移到队首。
  • 容量统计包含已过期但尚未清理的条目,可能触发一次额外淘汰。
  • now 可在测试中替换,生产默认 time.Now。
  • 值按值存储,存大对象时应改为指针或接口,避免复制开销。

验证方式

示例容量 2、TTL 50 毫秒:访问 a 后写入 c 会淘汰 b,等待 60 毫秒后 a 过期,最终 len=... 与统计符合预期。把 TTL 调大或去掉 sleep,可对比过期分支。