Golang缓存库,基于GCache做特性增强,支持设定过期缓存,LFU, LRU, ARC, Simple等缓存算法实现。
-
支持设定缓存失效时间:LFU, LRU and ARC;
-
支持协程安全;
-
支持监听缓存事件:evict, purge, added;(可选特性)
-
支持全局Loader自动加载不存在的键值;(可选特性)
-
支持外部化指定Loader加载不存在的键值;(通过
GetOrLoad
)
$ go get github.com/bytepowered/cache
package main
import (
"github.com/bytepowered/cache"
"fmt"
)
func main() {
gc := cache.New(20).
LRU().
Build()
gc.Set("key", "ok")
value, err := gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
}
Get: ok
package main
import (
"github.com/bytepowered/cache"
"fmt"
"time"
)
func main() {
gc := cache.New(20).
LRU().
Build()
gc.SetWithExpire("key", "ok", time.Second*10)
value, _ := gc.Get("key")
fmt.Println("Get:", value)
// Wait for value to expire
time.Sleep(time.Second*10)
value, err = gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
}
Get: ok
// 10 seconds later, new attempt:
panic: ErrKeyNotFound
package main
import (
"github.com/bytepowered/cache"
"fmt"
)
func main() {
gc := cache.New(20).
LRU().
LoaderFunc(func(key interface{}) (interface{}, error) {
return "ok", nil
}).
Build()
value, err := gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
}
Get: ok
package main
import (
"github.com/bytepowered/cache"
"fmt"
"time"
)
func main() {
gc := cache.New(20).
LRU().
Build()
value, err := gc.GetOrLoad("key",func(key interface{}) (cache.Expirable, error) {
return cache.NewDefault("my-new-value"), nil
})
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
}
Get: by-loader
package main
import (
"fmt"
"time"
"github.com/bytepowered/cache"
)
func main() {
var evictCounter, loaderCounter, purgeCounter int
gc := cache.New(20).
LRU().
LoaderExpireFunc(func(key interface{}) (cache.Expirable, error) {
loaderCounter++
return cache.NewExpirable("ok", time.Second*5), nil
}).
EvictedFunc(func(key, value interface{}) {
evictCounter++
fmt.Println("evicted key:", key)
}).
PurgeVisitorFunc(func(key, value interface{}) {
purgeCounter++
fmt.Println("purged key:", key)
}).
Build()
value, err := gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
time.Sleep(1 * time.Second)
value, err = gc.Get("key")
if err != nil {
panic(err)
}
fmt.Println("Get:", value)
gc.Purge()
if loaderCounter != evictCounter+purgeCounter {
panic("bad")
}
}
Get: ok
evicted key: key
Get: ok
purged key: key
- Least-Frequently Used (LFU)
Discards the least frequently used items first.
func main() {
// size: 10
gc := cache.New(10).
LFU().
Build()
gc.Set("key", "value")
}
- Least Recently Used (LRU)
Discards the least recently used items first.
func main() {
// size: 10
gc := cache.New(10).
LRU().
Build()
gc.Set("key", "value")
}
- Adaptive Replacement Cache (ARC)
Constantly balances between LRU and LFU, to improve the combined result.
detail: http://en.wikipedia.org/wiki/Adaptive_replacement_cache
func main() {
// size: 10
gc := cache.New(10).
ARC().
Build()
gc.Set("key", "value")
}
- SimpleCache (Default)
SimpleCache has no clear priority for evict cache. It depends on key-value map order.
func main() {
// size: 10
gc := cache.New(10).Build()
gc.Set("key", "value")
v, err := gc.Get("key")
if err != nil {
panic(err)
}
}
If specified LoaderFunc
, values are automatically loaded by the cache, and are stored in the cache until either evicted or manually invalidated.
func main() {
gc := cache.New(10).
LRU().
LoaderFunc(func(key interface{}) (interface{}, error) {
return "value", nil
}).
Build()
v, _ := gc.Get("key")
// output: "value"
fmt.Println(v)
}
GCache coordinates cache fills such that only one load in one process of an entire replicated set of processes populates the cache, then multiplexes the loaded value to all callers.
func main() {
// LRU cache, size: 10, expiration: after a hour
gc := cache.New(10).
LRU().
Expiration(time.Hour).
Build()
}
Event handler for evict the entry.
func main() {
gc := cache.New(2).
EvictedFunc(func(key, value interface{}) {
fmt.Println("evicted key:", key)
}).
Build()
for i := 0; i < 3; i++ {
gc.Set(i, i*i)
}
}
evicted key: 0
Event handler for add the entry.
func main() {
gc := cache.New(2).
AddedFunc(func(key, value interface{}) {
fmt.Println("added key:", key)
}).
Build()
for i := 0; i < 3; i++ {
gc.Set(i, i*i)
}
}
added key: 0
added key: 1
added key: 2
Yongjia Chen 2020 - 2021
Jun Kimura @2019