項目地址:https://github.com/patrickmn/go-cache
go-cache是一款類似於memached 的key/value 緩存。它比較適用於單機執行的應用程序。不需要額外部署服務,直接在內存中以map管理緩存的數據。
go-cache實質上就是擁有過期時間並且線程安全的map,可以被多個goroutine安全訪問。緩存過期策略爲lru策略。
項目主要代碼都在cache.go中,並僅需此一個文件即可
代碼邏輯清晰。主要是
type Item struct {
Object interface{}
Expiration int64
}
type Cache struct {
*cache
// If this is confusing, see the comment at the bottom of New()
}
type cache struct {
defaultExpiration time.Duration
items map[string]Item
mu sync.RWMutex
onEvicted func(string, interface{})
janitor *janitor
}
type janitor struct {
Interval time.Duration
stop chan bool
}
其中Item存儲了每條數據的信息
cache爲緩存的總的結構
janitor爲啓動器。
先說下這個janitor, 用戶調用new完成緩存的創立:
func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
items := make(map[string]Item)
return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
}
newCacheWithJanitor創立了cache對象,函數調用 runJanitor 創立了一個 goroutine完成緩存過期清理。同時使用了小技巧(查看源碼註釋)保證了緩存清理的goroutine的回收。
而cache提供了緩存的增刪改的功能,不再複述,其中用讀寫鎖對map進行多線程保護。
其中一個提高性能小技巧:爲了減少defer帶來的性能損耗,直接用unlock解鎖而不用defer
// TODO: Calls to mu.Unlock are currently not deferred because defer adds ~200 ns (as of go1.)
除了key-value類型的緩存,還支持計數類的緩存。
Sharded:
而此外項目提供的sharded.go,是提供了上述的標準方式的緩存的一種優化。
type unexportedShardedCache struct {
*shardedCache
}
type shardedCache struct {
seed uint32
m uint32
cs []*cache
janitor *shardedJanitor
}
最主要的優化點是用了cache數組(buckets),採用了djb33/djb2的散列方法(// djb2 with better shuffling. 5x faster than FNV with the hash.Hash overhead.)將緩存分佈於cache數組中
從而防止了寫的過程中對整個緩存的加鎖,提高了寫入性能。當然也帶來了一點內存的消耗和系統複雜度的提升。