group 简介
在软件系统中使用缓存,可以降低系统响应时间,提高用户体验,降低某些系统模块的压力.
group是一款开源的缓存组件.与mem与redis不同的时,groupcache不需要单独的部署,可以作为你程序的一个库来使用. 这样方便我们开发的程序部署.
本篇主要解析groupcache中的关键部分, lru的定义以及如何做到同一个key只加载一次。
缓存填充以及加载抑制的实现
loadsingleflight
callcallwg
type call struct { wg sync.WaitGroup val interface{} err error }
Groupcall
type Group struct { mu sync.Mutex // protects m m map[string]*call // lazily initialized }
Group.Domapmapkeycall
g.mu.Lock() if g.m == nil { g.m = make(map[string]*call) }
如果当前的key已经在请求加载的过程中,那么解除上一步定义的冲突锁,并等待已经存在的加载请求结束后返回。
if c, ok := g.m[key]; ok { g.mu.Unlock() c.wg.Wait() return c.val, c.err }
callmapcall.wg
c := new(call) c.wg.Add(1) g.m[key] = c g.mu.Unlock()
funccallwg.done
c.val, c.err = fn() c.wg.Done()
map
g.mu.Lock() delete(g.m, key) g.mu.Unlock()
sync.WaitGroup
cache(lru)
MaxEntriesOnEvictedllcache
type Cache struct { // MaxEntries is the maximum number of cache entries before // an item is evicted. Zero means no limit. MaxEntries int // OnEvicted optionally specifies a callback function to be // executed when an entry is purged from the cache. OnEvicted func(key Key, value interface{}) ll *list.List cache map[interface{}]*list.Element }
mapkeykeyindex
func (c *Cache) Add(key Key, value interface{}) { if c.cache == nil { c.cache = make(map[interface{}]*list.Element) c.ll = list.New() } if ee, ok := c.cache[key]; ok { c.ll.MoveToFront(ee) ee.Value.(*entry).value = value return } ele := c.ll.PushFront(&entry{key, value}) c.cache[key] = ele if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries { c.RemoveOldest() } }
清理时会删除尾部元素, 这里就解释了为什么每次操作时会把元素提到首位。
func (c *Cache) RemoveOldest() { if c.cache == nil { return } ele := c.ll.Back() if ele != nil { c.removeElement(ele) } }
本文由 华域联盟 原创撰写:准格尔旗术交电子产品销售服务部 » golang中cache组件的使用及groupcache源码解析