package lfu import ( "cache" "container/heap" ) // lfu // @Description:LFU,即最少使用,也就是淘汰缓存中访问频率最低的记录。 // LFU 认为,如果数据过去被访问多次,那么将来被访问的频率也更高。 // LFU 的实现需要维护一个按照访问次数排序的队列,每次访问,访问次数加 1,队列重新排序,淘汰时选择访问次数最少的即可 // 利用最小堆属性对访问次数排序实现 type lfu struct { // 缓存最大容量 maxBytes int // 当一个 entry 从缓存中移除时调用该回调函数,默认为 nil onEvicted func(key string, value any) //已使用的字节数,只包括值,key 不算 usedBytes int queue *queue cache map[string]*entry } func New(maxBytes int, onEvicted func(key string, value any)) cache.Cache { q := make(queue, 0, 1024) return &lfu{ maxBytes: maxBytes, onEvicted: onEvicted, queue: &q, cache: make(map[string]*entry), } } func (l *lfu) Set(key string, value any) { if e, ok := l.cache[key]; ok { l.usedBytes = l.usedBytes - cache.CalcLen(e.value) + cache.CalcLen(value) l.queue.update(e, value, e.weight+1) } else { en := &entry{key: key, value: value} //利用堆特性实现排序 heap.Push(l.queue, en) l.cache[key] = en l.usedBytes += en.Len() if l.maxBytes > 0 && l.usedBytes > l.maxBytes { l.removeElement(heap.Pop(l.queue)) } } } func (l *lfu) Get(Key string) any { if e, ok := l.cache[Key]; ok { l.queue.update(e, e.value, e.weight+1) return e.value } return nil } func (l *lfu) Del(Key string) { if e, ok := l.cache[Key]; ok { heap.Remove(l.queue, e.index) } } func (l *lfu) DelOldest() { if l.queue.Len() == 0 { return } l.removeElement(heap.Pop(l.queue)) } func (l *lfu) Len() int { return l.queue.Len() } func (l *lfu) removeElement(x any) { if x == nil { return } en := x.(*entry) delete(l.cache, en.key) l.usedBytes -= en.Len() if l.onEvicted != nil { l.onEvicted(en.key, en.value) } }