Go-cache-code-reading

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数组中

从而防止了写的过程中对整个缓存的加锁,提高了写入性能。当然也带来了一点内存的消耗和系统复杂度的提升。

 

0

发表评论