基于LRU算法引擎的简单缓存机制
一、缓存淘汰策略:
当缓存容量不足时,将最近最少使用到的缓存直接淘汰掉。
二、实现数据结构
双向链表+字典
三、实现大体思路
先上核心代码吧
` /// <summary>
/// 基于LRU算法的缓存机制
/// 实现数据结构:双向链表+字典
/// </summary>
public class CacheLRUEngine<K,V>
{
//双向链表,维护key是否被使用
private DoublyLinkedList<K> _keyLruQue = new DoublyLinkedList<K>();
//数据存储字典
private Dictionary<K, V> _cacheMemory = new Dictionary<K, V>();
//key和链表节点的字典
private Dictionary<K, DoublyNode<K>> _keyToNodeMap = new Dictionary<K, DoublyNode<K>>();
//缓存容量
private Int32 _capacity = 100000;
//缓存大小
private Int32 _size = 0;
public Int32 Capacity
{
get
{
return _capacity;
}
set
{
if (value <= 0)
throw new NonpositiveException("缓存容量必须大于零");
_capacity = value;
}
}
public Int32 Size
{
get {
return _size;
}
}
public bool Set(K key,V value)
{
try
{
if (_cacheMemory.ContainsKey(key))
{
_cacheMemory.Add(key, value);
}
else
{
if (_capacity - _size <= 0)
{
//删除最近最少使用的缓存
DelLRUCache();
_size--;
}
_cacheMemory.Add(key, value);
_keyToNodeMap.Add(key, _keyLruQue.Push(key));
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
_size++;
return true;
}
public V Get(K key)
{
if (_cacheMemory.ContainsKey(key))
{
//从key-node映射字典中获取到key对应的节点
_keyToNodeMap.TryGetValue(key, out DoublyNode<K> node);
//从LRU队列中删除key对应的节点
node.PrePoint.NextPoint = node.NextPoint;
node.NextPoint.PrePoint = node.PrePoint;
node = null;
//将key加入到LRU队列头部
DoublyNode<K> addr = _keyLruQue.Push(key);
//跟新映射
_keyToNodeMap.Remove(key);
_keyToNodeMap.Add(key, addr);
//返回渠道的值
bool res = _cacheMemory.TryGetValue(key, out V value);
return res ? value : default(V);
}
else
{
throw new NonCacheException("key不存在");
}
}
private bool DelLRUCache()
{
K tempKey = _keyLruQue.Tail.Value;
_keyLruQue.DelFromTail();
_keyToNodeMap.Remove(tempKey);
_cacheMemory.Remove(tempKey);
return true;
}
//删除缓存
public bool DelCacheByKey(K key)
{
if (!_cacheMemory.ContainsKey(key))
return true;
_keyToNodeMap.TryGetValue(key,out DoublyNode<K> node);
_keyLruQue.DelNode(node);
_keyToNodeMap.Remove(key);
_cacheMemory.Remove(key);
return true;
}
}`
_keyLruQue双向链表为自实现双向链表数据结构,该双向链表主要负责维护LRU机制,链表头部是最近使用最多的数据,尾部是最近使用次数最少的数据。
_cacheMemory该字典用作数据存储器,是存储key-value被缓存数据的核心存储器。
_keyToNodeMap为key到对应链表节点的映射字典,可通过key找到_keyLruQue中对应的链表节点。
四、set方法的工作机制
当需要想cache中加入缓存时:
1.检查key是否已经存在,如果已经存在的话,则覆盖原来的值
2.如果不存在,则先去检查缓存容量是否足够,如果不足够,则删除_keyLruQue双向链表尾部的key对应的缓存,并将数据缓存入存储器。
3.容量足够则直接存入存储器。
五、get方法的工作机制
当需要从缓存中获取数据时:
1.根据key从_keyToNodeMap中获取到对应的链表节点,将该节点移动到_keyLruQue头部。
2.从_cacheMemory中获取到数据,直接返回即可。