安装
1 go get github.com/patrickmn/go-cache
使用方法
import ( "fmt" "github.com/patrickmn/go-cache" "time" ) func main() { // Create a cache with a default expiration time of 5 minutes, and which // purges expired items every 10 minutes
// 默认5分钟过期,每10分钟删除过期的项目 c := cache.New(5*time.Minute, 10*time.Minute) // Set the value of the key "foo" to "bar", with the default expiration time
// 设置缓存,使用默认过期时间 c.Set("foo", "bar", cache.DefaultExpiration) // Set the value of the key "baz" to 42, with no expiration time // (the item won't be removed until it is re-set, or removed using // c.Delete("baz")
// 使用不过期策略,除非重新设置了或者使用了Delete方法,否则数据将一直不会被删除,即使是每10分钟的清理也不会 c.Set("baz", 42, cache.NoExpiration) // Get the string associated with the key "foo" from the cache 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) // ... } }
过期机制
过期有两种,一种是时间过期,一种是淘汰过期。Guava在构建Cache对象时,可以通过CacheBuilder类的expireAfterAccess和expireAfterWrite两个方法为缓存中的对象指定过期时间,过期的对象将会被缓存自动删除。其中,expireAfterWrite方法指定对象被写入到缓存后多久过期,expireAfterAccess指定对象多久没有被访问后过期。go-cache采用的是时间过期方法,且仅支持expireAfterWrite。
GC
go-cache使用了goroutine执行自动过期清理。当整个cache都不再被使用者需要了,应该被GC,但是由于后台清理goroutine的存在,整个cache将不会被回收掉。go-cache中使用了runtime.SetFinalizer,
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 }
对SetFinalizer的解释,我引用下别人的