您的位置:首页 > 其它

LRU算法实现

2016-10-22 14:25 211 查看
LRU

LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:

新数据插入到链表头部;

每当缓存命中(即缓存数据被访问),则将数据移到链表头部;

当链表满的时候,将链表尾部的数据丢弃。

【命中率】

当存在热点数据时,LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降,缓存污染情况比较严重。

【复杂度】

实现简单。

【代价】

命中时需要遍历链表,找到命中的数据块索引,然后需要将数据移到头部。

这是go利用container/list实现版本,出自Brad Fitzpatrick之手

Cache对象是内存中的一个容器,用来存放查询的结果。我们将Cache对象实现为一个List。另外,为了提升访问效率,用一个map结构来索引key及其对应的值。

// Cache is an LRU cache. It is not safe for concurrent access.
type Cache struct {
// MaxEntries is the maximum number of cache entries before
// an item is evicted. Zero means no limit.
MaxEntries int

// OnEvicted optionally specificies a callback function to be
// executed when an entry is purged from the cache.
OnEvicted func(key Key, value interface{})

// type List struct {
//  root Element // sentinel list element, only &root, root.prev, and root.next are used
//  len  int     // current list length excluding (this) sentinel element
// }

// type Element struct {
//  // Next and previous pointers in the doubly-linked list of elements.
//  // To simplify the implementation, internally a list l is implemented
//  // as a ring, such that &l.root is both the next element of the last
//  // list element (l.Back()) and the previous element of the first list
//  // element (l.Front()).
//  next, prev *Element

//  // The list to which this element belongs.
//  list *List

//  // The value stored with this element.
//  Value interface{}
// }

ll    *list.List
cache map[interface{}]*list.Element
}

// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators type Key interface{}

//在list中存放的是entry
type entry struct {
key   Key
value interface{}
}

// New creates a new Cache.
// If maxEntries is zero, the cache has no limit and it's assumed
// that eviction is done by the caller.
func New(maxEntries int) *Cache {
return &Cache{
MaxEntries: maxEntries,
ll:         list.New(),
cache:      make(map[interface{}]*list.Element),
}
}

// Add adds a value to the cache.
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
}
//返回Element作为map的value
ele := c.ll.PushFront(&entry{key, value})
c.cache[key] = ele
if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries {
//执行清理
c.RemoveOldest()
}
}

// Get looks up a key's value from the cache.
func (c *Cache) Get(key Key) (value interface{}, ok bool) {
if c.cache == nil {
return
}
if ele, hit := c.cache[key]; hit {
c.ll.MoveToFront(ele)
return ele.Value.(*entry).value, true
}
return
}

// Remove removes the provided key from the cache.
func (c *Cache) Remove(key Key) {
if c.cache == nil {
return
}
if ele, hit := c.cache[key]; hit {
c.removeElement(ele)
}
}

// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() {
if c.cache == nil {
return
}
ele := c.ll.Back()
if ele != nil {
c.removeElement(ele)
}
}

func (c *Cache) removeElement(e *list.Element) {
c.ll.Remove(e)
kv := e.Value.(*entry)
delete(c.cache, kv.key)
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}

// Len returns the number of items in the cache.
func (c *Cache) Len() int {
if c.cache == nil {
return 0
}
return c.ll.Len()
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 链表 缓存