feat: LRU缓存实现

dev
old-tom 2 years ago
parent d49f187da6
commit 4fc1cae2da

23
.gitignore vendored

@ -0,0 +1,23 @@
### Go template
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work

@ -9,6 +9,7 @@ import (
// @Description:LFU即最少使用也就是淘汰缓存中访问频率最低的记录。 // @Description:LFU即最少使用也就是淘汰缓存中访问频率最低的记录。
// LFU 认为,如果数据过去被访问多次,那么将来被访问的频率也更高。 // LFU 认为,如果数据过去被访问多次,那么将来被访问的频率也更高。
// LFU 的实现需要维护一个按照访问次数排序的队列,每次访问,访问次数加 1队列重新排序淘汰时选择访问次数最少的即可 // LFU 的实现需要维护一个按照访问次数排序的队列,每次访问,访问次数加 1队列重新排序淘汰时选择访问次数最少的即可
// 利用最小堆属性对访问次数排序实现
type lfu struct { type lfu struct {
// 缓存最大容量 // 缓存最大容量
maxBytes int maxBytes int
@ -41,7 +42,7 @@ func (l *lfu) Set(key string, value any) {
l.cache[key] = en l.cache[key] = en
l.usedBytes += en.Len() l.usedBytes += en.Len()
if l.maxBytes > 0 && l.usedBytes > l.maxBytes { if l.maxBytes > 0 && l.usedBytes > l.maxBytes {
l.removeElement(heap.Pop(l.queue))
} }
} }
} }
@ -61,11 +62,14 @@ func (l *lfu) Del(Key string) {
} }
func (l *lfu) DelOldest() { func (l *lfu) DelOldest() {
if l.queue.Len() == 0 {
return
}
l.removeElement(heap.Pop(l.queue))
} }
func (l *lfu) Len() int { func (l *lfu) Len() int {
return 0 return l.queue.Len()
} }
func (l *lfu) removeElement(x any) { func (l *lfu) removeElement(x any) {
@ -75,4 +79,7 @@ func (l *lfu) removeElement(x any) {
en := x.(*entry) en := x.(*entry)
delete(l.cache, en.key) delete(l.cache, en.key)
l.usedBytes -= en.Len() l.usedBytes -= en.Len()
if l.onEvicted != nil {
l.onEvicted(en.key, en.value)
}
} }

@ -0,0 +1,34 @@
package lfu_test
import (
"cache/lfu"
"github.com/matryer/is"
"testing"
)
func TestSet(t *testing.T) {
is := is.New(t)
cache := lfu.New(24, nil)
cache.DelOldest()
cache.Set("k1", 1)
v := cache.Get("k1")
is.Equal(v, 1)
cache.Del("k1")
is.Equal(0, cache.Len())
}
func TestOnEvicted(t *testing.T) {
is := is.New(t)
keys := make([]string, 0, 8)
onEvicted := func(key string, value interface{}) {
keys = append(keys, key)
}
cache := lfu.New(32, onEvicted)
cache.Set("k1", 1)
cache.Set("k2", 2)
cache.Set("k3", 3)
cache.Set("k4", 4)
expected := []string{"k1", "k3"}
is.Equal(expected, keys)
is.Equal(2, cache.Len())
}
Loading…
Cancel
Save