go-cache
是一个基于内存的、高速的,存储k-v
格式的缓存工具。它适用于运行在单台机器上的应用程序,可以存储任何数据类型的值,并可以被多个goroutine
安全地使用。
虽然go-cache
不打算用作持久数据存储,但是可以将整个缓存数据保存到文件(或任何io.Reader/Writer
)中,并且能快速从中指定数据源加载,快速恢复状态。
go get github.com/patrickmn/go-cache
import (
"fmt"
"github.com/patrickmn/go-cache"
"time"
)
func main() {
// 默认过期时间为5min,每10min清理一次过期缓存
c := cache.New(5*time.Minute, 10*time.Minute)
// 设置key-value,并设置为默认过期时间
c.Set("foo", "bar", cache.DefaultExpiration)
// 设置一个不会过期的key,该key不会自动删除,重新更新key或者使用c.Delete("baz")
c.Set("baz", 42, cache.NoExpiration)
// 从缓存获取对应key的值
foo, found := c.Get("foo")
if found {
fmt.Println(foo)
}
// Since Go is statically typed, and cache values can be anything, type
// assertion is needed when values are being passed to functions that don't
// take arbitrary types, (i.e. interface{}). The simplest way to do this for
// values which will only be used once--e.g. for passing to another
// function--is:
foo, found := c.Get("foo")
if found {
MyFunction(foo.(string))
}
// This gets tedious if the value is used several times in the same function.
// You might do either of the following instead:
if x, found := c.Get("foo"); found {
foo := x.(string)
// ...
}
// or
var foo string
if x, found := c.Get("foo"); found {
foo = x.(string)
}
// ...
// foo can then be passed around freely as a string
// Want performance? Store pointers!
c.Set("foo", &MyStruct, cache.DefaultExpiration)
if x, found := c.Get("foo"); found {
foo := x.(*MyStruct)
// ...
}
}
defer
的使用defer
是一个很强大的机制,尤其是在资源释放的场景特别适用。但是使用时要注意,defer是有不小的性能损耗,且过度使用后也会导致逻辑变复杂。go-cache
源码中没有使用defer
,也做了相应的注释。
func (c *cache) Set(k string, x interface{}, d time.Duration) {
// "Inlining" of set
var e int64
if d == DefaultExpiration {
d = c.defaultExpiration
}
if d > 0 {
e = time.Now().Add(d).UnixNano()
}
c.mu.Lock()
c.items[k] = Item{
Object: x,
Expiration: e,
}
// TODO: Calls to mu.Unlock are currently not deferred because defer
// adds ~200 ns (as of go1.)
c.mu.Unlock()
}
SetFinalizer
的使用在Go中,finalizer
函数是当对象不在被引用,对象被GC进程选中并从内存中移除的时候将其调用,有点类似析构函数。可以使用runtime.SetFinalizer
函数向对象添加finalizer
。
func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
c := newCache(de, m)
// This trick ensures that the janitor goroutine (which--granted it
// was enabled--is running DeleteExpired on c forever) does not keep
// the returned C object from being garbage collected. When it is
// garbage collected, the finalizer stops the janitor goroutine, after
// which c can be collected.
C := &Cache{c}
if ci > 0 {
runJanitor(c, ci)
runtime.SetFinalizer(C, stopJanitor)
}
return C
}
文档地址
golang defer使用需要注意
垃圾回收和 SetFinalizer
Go 性能优化技巧 10/10
go中的finalizer