Go实现LRU Cache

在web程序开发中,一般会使用redis作为数据缓存缓存一些常用的数据。但是有时候,当访问量特别巨大的时候,redis也不一定能抵挡这么大的流量的时候,一般会将常用的数据放入内存中,避难频繁访问redis。

由于内存的资源相对比较昂贵,我们需要对放入内存中的数据做一些限制以及将一些不常用的数据清理出去。这个时候就需要用到LRU算法(Least recently used,最近最少使用)。

LSU cache是一种常见的缓存置换算法。会根据缓存访问的频繁程度,将不常用的缓存逐渐淘汰掉,以释放内存资源。

在go语言中,利用自带的list双向链表可以实现相关算法功能,以下为代码示例

package lru_cache

import (
    "container/list"
    "sync"
)

type Lrc struct {
    size     int
    list     *list.List
    cacheMap map[string]*list.Element
    lock     sync.RWMutex
}

type data struct {
    key   string
    value interface{}
}

func NewLrc(size int) *Lrc {
    return &Lrc{
        size:     size,
        list:     list.New(),
        cacheMap: make(map[string]*list.Element),
    }
}

// Set 写入缓存
func (l *Lrc) Set(key string, value interface{}) {
    l.lock.Lock()
    defer l.lock.Unlock()

    // 判断是否已经存在
    if elem, ok := l.cacheMap[key]; ok {
        l.list.MoveToFront(elem)
        elem.Value.(*data).value = value
        return
    }

    item := &data{
        key:   key,
        value: value,
    }
    elem := l.list.PushFront(item)
    l.cacheMap[key] = elem

    // 判断是否超过长度限制
    if l.list.Len() > l.size && l.size > 0 {
        deleteItem := l.list.Back()
        l.list.Remove(deleteItem)
        deleteKey := deleteItem.Value.(*data).key
        delete(l.cacheMap, deleteKey)
    }
}

// Get 读取缓存
func (l *Lrc) Get(key string) (interface{}, bool) {
    l.lock.RLock()
    value, ok := l.cacheMap[key]
    l.lock.RUnlock()

    if ok {
        l.lock.Lock()
        l.list.MoveToFront(value)
        l.lock.Unlock()
        return value.Value.(*data).value, true
    } else {
        return nil, false
    }
}

// Delete 缓存
func (l *Lrc) Delete(key string) {
    l.lock.RLock()
    value, ok := l.cacheMap[key]
    l.lock.RUnlock()

    if ok {
        l.lock.Lock()
        l.list.Remove(value)
        key := value.Value.(*data).key
        delete(l.cacheMap, key)
        l.lock.Unlock()
    }
}

github

你可能感兴趣的:(go算法)