LRU最近最少使用缓存集合
编码中涉及到资源管理就会经常使用到最近最少使用淘汰原理(LRU),比如说最近打开的文章列表管理、或者游戏中动态加载地图、音乐一样。使用LRU可以提高效率。本文实现了一个完整功能的LRU集合,可用于各种诸如此类需要缓存机制的地方。
/// <summary> /// 使用最近最少算法进行淘汰的缓存集合,用于缓存数据. /// 提供了多线程安全访问功能 /// </summary> /// <remarks> /// 1、调用方在每使用一个数据之后,调用UpdateRecentlyUsed函数将该数据 /// 置为最近访问。函数会将该条目的读取权值设为最大值。 /// 2、在使用Add或者Insert添加条目时,如果缓存数目已达到设定的CacheSize值, /// 则会根据删除掉缓存列表中读取权值最小的条目。再进行添加 /// </remarks> public class LRUCacheList<T> : IList<T> { #region Property /// <summary> /// 实际存放缓存条目的列表 /// </summary> private List<T> m_listData; /// <summary> /// 存放与m_listData依次对应条目的最近读取记录 /// </summary> private List<uint> m_listReadWeight; /// <summary> /// 当前最大的读取记录权值,用来计算下一个读取值 /// </summary> private uint m_iMaxWeight; /// <summary> /// 一个无符号整数的最大值 /// </summary> private const uint c_MaxWeight = 0xffffffff; private Object m_lockObj = new object(); /// <summary> /// 读取和设置缓存大小,指定最多缓存的对象数目 /// </summary> public int CacheSize { get; set; } #endregion #region Method /// <summary> /// /// </summary> /// <param name="cacheSize">缓存数目</param> public LRUCacheList(int cacheSize) { m_listData = new List<T>(cacheSize); m_listReadWeight = new List<uint>(cacheSize); CacheSize = cacheSize; } /// <summary> /// 移除掉最近最少使用的条目 /// </summary> protected void RemoveLeastRecentlyUsed() { lock (m_lockObj) { uint min = c_MaxWeight; int minIndex = -1; for (int i = 0; i < m_listReadWeight.Count; i++) { if (m_listReadWeight[i] < min) { min = m_listReadWeight[i]; minIndex = i; } } if (minIndex != -1) { m_listReadWeight.RemoveAt(minIndex); m_listData.RemoveAt(minIndex); } } } /// <summary> /// 更新指定位置的权重值为最近访问 /// </summary> /// <param name="index"></param> public void UpdateRecentlyUsed(T item) { lock (m_lockObj) { int index = m_listData.IndexOf(item); if (index != -1) UpdateRecentlyUsed(index); } } /// <summary> /// 更新指定位置的权重值为最近访问 /// </summary> /// <param name="index"></param> public void UpdateRecentlyUsed(int index) { m_listReadWeight[index] = NextMaxWeight(); } /// <summary> /// 清除掉所有缓存的内容 /// </summary> public void Clear() { lock (m_lockObj) { if (m_listData != null) m_listData.Clear(); if (m_listReadWeight != null) m_listReadWeight.Clear(); m_iMaxWeight = 0; } } /// <summary> /// 获取并设置下一个最大的权重值 /// </summary> /// <returns></returns> public uint NextMaxWeight() { lock (m_lockObj) { //到达最大值重置 if (m_iMaxWeight == c_MaxWeight - 1) { m_iMaxWeight = 0; for (int i = 0; i < m_listReadWeight.Count; i++) { m_listReadWeight[i] = 0; } } m_iMaxWeight++; return m_iMaxWeight; } } /// <summary> /// 添加一个条目并设置为最近访问 /// </summary> /// <param name="item"></param> public void AddRecently(T item) { lock (m_lockObj) { while (CacheSize > 0 && m_listData.Count >= CacheSize) RemoveLeastRecentlyUsed(); m_listData.Add(item); m_listReadWeight.Add(NextMaxWeight()); } } /// <summary> /// 插入一个条目并设置为最近访问 /// </summary> /// <param name="index"></param> /// <param name="item"></param> public void InsertRecently(int index, T item) { lock (m_lockObj) { while (CacheSize > 0 && m_listData.Count >= CacheSize) RemoveLeastRecentlyUsed(); m_listData.Insert(index, item); m_listReadWeight.Insert(index, NextMaxWeight()); } } #endregion #region 实现IList<T> 接口 public void Add(T item) { lock (m_lockObj) { while (CacheSize > 0 && m_listData.Count >= CacheSize) RemoveLeastRecentlyUsed(); m_listData.Add(item); m_listReadWeight.Add(0); } } /// <summary> /// /// </summary> /// <param name="item"></param> /// <returns></returns> public int IndexOf(T item) { return m_listData.IndexOf(item); } public void Insert(int index, T item) { lock (m_lockObj) { while (CacheSize > 0 && m_listData.Count >= CacheSize) RemoveLeastRecentlyUsed(); m_listData.Insert(index, item); m_listReadWeight.Insert(index, 0); } } public void RemoveAt(int index) { lock (m_lockObj) { m_listData.RemoveAt(index); m_listReadWeight.RemoveAt(index); } } public T this[int index] { get { return m_listData[index]; } set { m_listData[index] = value; } } public bool Contains(T item) { return m_listData.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { m_listData.CopyTo(array, arrayIndex); } public int Count { get { return m_listData.Count; } } public bool IsReadOnly { get { return false; } } public bool Remove(T item) { lock (m_lockObj) { int index = m_listData.IndexOf(item); if (index != -1) m_listReadWeight.RemoveAt(index); return m_listData.Remove(item); } } public IEnumerator<T> GetEnumerator() { return m_listData.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return m_listData.GetEnumerator(); } #endregion }