Go cache 源碼閱讀

項目地址: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數組中

從而防止了寫的過程中對整個緩存的加鎖,提高了寫入性能。當然也帶來了一點內存的消耗和系統複雜度的提升。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章