7リンクリスト:(下)LRUキャッシュ

1.原則

 

LRU(Least Recently Used)アルゴリズムは、データの履歴アクセスレコードに基づいてデータを削除します。データが最近アクセスされた場合、将来アクセスされる可能性も高くなります。

この原理によれば、マイクロサービスの二次キャッシュ構造は、頻繁にアクセスされるホットデータを格納するように設計でき、バックエンドデータベースへの頻繁なアクセスを回避する同じデータロジックを実現します。このキャッシュを二次キャッシュとして使用する場合、キャッシュ内のデータとバックエンドデータの整合性を確保する必要があります。

2.実装

lrucacheの実装では、リンクリストを使用してキャッシュデータを保存します。詳細なアルゴリズムは次のとおりです。

 

  1. リンクされたリストの最後に新しいデータが挿入されます。

  2. キャッシュがヒットする(つまり、キャッシュされたデータがアクセスされる)と、データはリンクリストの最後に移動されます。

  3. リンクリストがいっぱいになると、リンクリストの先頭にあるデータは破棄されます。

3.分析

[ヒット率]ホットデータが存在する場合、LRUの効率は非常に良好ですが、時々または定期的なバッチ操作によりLRUヒット率が急激に低下し、キャッシュの汚染がより深刻になります。

【複雑さ】

O(1)-O(n)

【費用】

ヒットするときは、リンクリストをたどってヒットデータブロックのインデックスを見つけてから、データを先頭に移動する必要があります。

ロジックフロー:

github関連リソース:

https://github.com/yiekue/lru4go

https://github.com/wonderivan/lrucache

https://github.com/wonderivan/craw

実装1:

package main;
 
import (
    "container/list"
    "errors"
    "sync"
    "fmt"
    "encoding/json"
)
 
//LRU(Least recently used)最近最少使用,算法根据数据的历史访问记录来进行淘汰数据
//核心思想是"如果数据最近被访问过,那么将来被访问的几率也更高"
//常见的实现方式是用一个链表保存数据
//1. 新数据插入到链表头部
//2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部
//3. 当链表满的时候,将链表尾部的数据丢弃
 
type cacheItem struct {
    Key string;
    Val interface{};
}
 
type LRU struct {
    //最大存储数量
    maxNum int;
    //当前存储数量
    curNum int;
    //锁,保证数据一致性
    mutex  sync.Mutex;
    //链表
    data   *list.List;
}
 
//添加数据
func (l *LRU) add(key string, value interface{}) error {
    //判断key是否存在
    if e, _ := l.exist(key); e {
        return errors.New(key + "已存在");
    }
    //判断当前存储数量与最大存储数量
    if l.maxNum == l.curNum {
        //链表已满,则删除链表尾部元素
        l.clear();
    }
    l.mutex.Lock();
    l.curNum++;
    //json序列化数据
    data, _ := json.Marshal(cacheItem{key, value});
    //把数据保存到链表头部
    l.data.PushFront(data);
    l.mutex.Unlock();
    return nil;
}
 
//设置数据
func (l *LRU) set(key string, value interface{}) error {
    e, item := l.exist(key);
    if !e {
        return l.add(key, value);
    }
    l.mutex.Lock();
    data, _ := json.Marshal(cacheItem{key, value});
    //设置链表元素数据
    item.Value = data;
    l.mutex.Unlock();
    return nil;
}
 
//清理数据
func (l *LRU) clear() interface{} {
    l.mutex.Lock();
    l.curNum--;
    //删除链表尾部元素
    v := l.data.Remove(l.data.Back());
    l.mutex.Unlock();
    return v;
}
 
//获取数据
func (l *LRU) get(key string) interface{} {
    e, item := l.exist(key);
    if !e {
        return nil;
    }
    l.mutex.Lock();
    //数据被访问,则把元素移动到链表头部
    l.data.MoveToFront(item);
    l.mutex.Unlock();
    var data cacheItem;
    json.Unmarshal(item.Value.([]byte), &data);
    return data.Val;
}
 
//删除数据
func (l *LRU) del(key string) error {
    e, item := l.exist(key);
    if !e {
        return errors.New(key + "不存在");
    }
    l.mutex.Lock();
    l.curNum--;
    //删除链表元素
    l.data.Remove(item);
    l.mutex.Unlock();
    return nil;
}
 
//判断是否存在
func (l *LRU) exist(key string) (bool, *list.Element) {
    var data cacheItem;
    //循环链表,判断key是否存在
    for v := l.data.Front(); v != nil; v = v.Next() {
        json.Unmarshal(v.Value.([]byte), &data);
        if key == data.Key {
            return true, v;
        }
    }
    return false, nil;
}
 
//返回长度
func (l *LRU) len() int {
    return l.curNum;
}
 
//打印链表
func (l *LRU) print() {
    var data cacheItem;
    for v := l.data.Front(); v != nil; v = v.Next() {
        json.Unmarshal(v.Value.([]byte), &data);
        fmt.Println("key:", data.Key, " value:", data.Val);
    }
}
 
//创建一个新的LRU
func LRUNew(maxNum int) *LRU {
    return &LRU{
        maxNum: maxNum,
        curNum: 0,
        mutex:  sync.Mutex{},
        data:   list.New(),
    };
}
 
func main() {
    lru := LRUNew(5);
    lru.add("1111", 1111);
    lru.add("2222", 2222);
    lru.add("3333", 3333);
    lru.add("4444", 4444);
    lru.add("5555", 5555);
    lru.print();
    //get成功后,可以看到3333元素移动到了链表头
    fmt.Println(lru.get("3333"));
    lru.print();
    //再次添加元素,如果超过最大数量,则删除链表尾部元素,将新元素添加到链表头
    lru.add("6666", 6666);
    lru.print();
    lru.del("4444");
    lru.print();
    lru.set("2222", "242424");
    lru.print();
}

送信元:https : //www.cnblogs.com/jkko123/p/6971133.html

 

情報リンク2:

https://www.jianshu.com/p/2aff66fac48a

 

 

公開された127元の記事 ウォン称賛24 ビュー130 000 +

おすすめ

転載: blog.csdn.net/Linzhongyilisha/article/details/99355436