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。git
go-cache使用了goroutine執行自動過時清理。當整個cache都再也不被使用者須要了,應該被GC,可是因爲後臺清理goroutine的存在,整個cache將不會被回收掉。go-cache中使用了runtime.SetFinalizer,github
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的解釋,我引用下別人的緩存
對象能夠關聯一個SetFinalizer函數, 當gc檢測到unreachable對象有關聯的SetFinalizer函數時,會執行關聯的SetFinalizer函數, 同時取消關聯。 這樣當下一次gc的時候,對象從新處於unreachable狀態而且沒有SetFinalizer關聯, 就會被回收。--https://zhuanlan.zhihu.com/p/76504936app
在這種場景下,每每須要一個wrapper來包一層。在go-cache的代碼中,newCache()方法返回的是*cache,而綁定Setfinalizer的函數對象則是*Cache(注意大小寫)。 函數