cache2go 支持过期的并发安全 go 缓存库,适合新手阅读学习。
cache2go 使用 map 作为存储 item 的容器,使用定时器进行过期检测,同时支持时间触发回调。
安装
go get github.com/muesli/cache2go |
官方使用示例
// Keys & values in cache2go can be of arbitrary types, e.g. a struct. |
使用示例补充
注册 item 过期删除回调
SetAboutToExpireCallback和AddAboutToExpireCallback都可以进行 item 鼓起删除回调注册,区别是SetAboutToExpireCallback会删除掉之前注册的过期删除回到,而AddAboutToExpireCallback则只会向后追加。
另外,除了超时以外,Delete也可以触发过期删除回调操作。
func main() { |
hello deleted |
核心数据结构梳理
CacheTable
type CacheTable struct { |
- sync.RWMutex
一把读写锁,用于控制并发读写 - name
缓存表名,用于区分不同表 - items
实际存储缓存对象的地方,是一个 map。也就是 key 支持 comparable 对象,而不是所有类型。比如 slice、func、map 等就不支持。 - cleanupTimer
用于触发清理任务的定时器 - cleanupInterval
上次清理到现在的时间 - logger
日志组件 - loadData
读取不存在的 key 时触发的回调方法 - addItem
当添加新 item 时触发的回调方法 - aboutToDeleteItem
删除 item 前触发的回调方法
CacheItem
// CacheItem is an individual cache item |
- lifeSpan
未被访问后存活的时长 - createdOn
创建时间 - accessedOn
最后一次访问时间,配合 lifeSpan 进行生命周期判定 - accessCount
访问计数 - aboutToExpire
在被移除前触发的回调方法
执行流程梳理
Cache
我们可以通过Cache获取一个 cache table,如这个cache table不存在,则会创建一个新的。执行流程如下:
- 在读锁保护下获取名为 name 的
cache table信息 - 判断是否存在,如果存在则直接返回,否则执行 3
- 在写锁保护下,再次检查是否存在对应
cache table,如果不存在则创建并注册到 cache 中,否则返回。再次判断是为了避免在未持有锁期间其他协程进行了创建操作引起的并发问题。
mutex & cache 私有全集变量
var ( |
func Cache(table string) *CacheTable { |
Add
通过Add方法我们可以向CacheTable存入 item。执行流程如下:
根据参数创建 item
加锁进行表更新操作
- 更新
table.items,如果有 key 相同的 item 会被覆盖掉。 - 缓存
table.cleanupInterval``table.addedItem后释放锁 - 执行
table.addedItem回调函数 - 如果存入的 item 不是永久有效并且没有触发过过期检测或者 item 过期时长小于下一次触发间隔,则执行更新间隔操作
- 更新
返回 item,这使得我们可以对 item 添加回调方法。
func (table *CacheTable) Add(key interface{}, lifeSpan time.Duration, data interface{}) *CacheItem { |
func (table *CacheTable) addInternal(item *CacheItem) { |
Value
我们使用Value方法获取缓存的 item,执行流程如下:
- 在读锁保护性获取对应 item 信息,同时混村
table.loadData回调 - 判断 item 是否存在,存在则执行 KeepAlive 方法,更新最后一次访问时间和访问计数器,同时返回 item。否则执行 3
- 判断是否注册了 loadData,如果有则执行 loadData 尝试加载 item,成功则返回 item,否则返回错误
ErrKeyNotFoundOrLoadable
func (table *CacheTable) Value(key interface{}, args ...interface{}) (*CacheItem, error) { |
Delete
- 获取写锁,并利用 defer 在流程结束后进行一次释放锁操作。
- 检查 key 是否存在,不存在直接报错。否则执行 3。
- 缓存
table.aboutToDeleteItem回调函数,并释放锁资源。 - 如果
table.aboutToDeleteItem不为 nil 则执行 - 获取读锁,如果注册了过期回调则执行。
- 加写锁,删除 item,并返回。
// Delete an item from the cache. |
func (table *CacheTable) deleteInternal(key interface{}) (*CacheItem, error) { |
Flush
- 加写锁,使用 defer 实现流程结束后释放锁
- 创建新的
table.items覆盖原来的,让 GC 自行清理数据。 - 重置定时器信息。
// Flush deletes all items from this cache table. |
- 本文作者: Tiny Beer
- 本文链接: https://tinybeer.github.io/2024/06/01/cache2go/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!
