1. 程式人生 > >c# LRU實現的快取類

c# LRU實現的快取類

在網上找到網友中的方法,將其修改整理後,實現了快取量控制以及時間控制,如果開啟快取時間控制,會降低效率。

定義列舉,移除時使用

public enum RemoveType     {         [Description("超時移除")]         TimeOut,         [Description("超量移除")]         Capacity     }

定義委託,移除時使用

 public delegate void RemoveKV<Tkey, TValue>(string cacheName, RemoveEntity<Tkey, TValue> entity);

定義快取類

 public class LRUCache<TKey, TValue>     {        const  int DEFAULT_CAPACITY = int.MaxValue;

        private int _capacity;         private  ReaderWriterLockSlim locker;         private  IDictionary<TKey, TValue> dictionary;//資料         private LinkedList<TKey> linkedList;//控制Key的資料         private Dictionary<TKey, LinkedListNode<TKey>> dicLinkIndex = null;//控制刪除         private Dictionary<TKey, long> dicRefresh = null;//使用時間         private volatile bool isCheckTime = false;//設定是否監測快取的時間長度         private  long cacheTime = 600;//10分鐘         private volatile bool isCheckThread = false;//檢查執行緒啟動         private long checkTicks = 0;//換算後的時間         private BlockingCollection<RemoveEntity<TKey, TValue>> removeEntities = null;         public event RemoveKV<TKey, TValue> RemoveEntitiesEvent = null;//移除通知         private DateTime checkTime = DateTime.Now;//結束監測的時間

        /// <summary>         /// 設定快取的時間長度,當前按照秒算         /// 設定時間自動設定屬性IsCacheCheckTime=true         /// </summary>         public long CacheTime { get { return cacheTime; } set { cacheTime = value;isCheckTime = true; countTime(); } }

        /// <summary>         /// 是否監測時間         /// </summary>         public bool IsCacheCheckTime { get { return isCheckTime; } set { isCheckTime = value; countTime(); } }

        /// <summary>         /// cache名稱         /// </summary>         public string CacheName { get; set; }

        public LRUCache() : this(DEFAULT_CAPACITY) { }

        public LRUCache(int capacity)         {             locker = new ReaderWriterLockSlim();             _capacity = capacity > 0 ? capacity : DEFAULT_CAPACITY;             dictionary = new Dictionary<TKey, TValue>();             linkedList = new LinkedList<TKey>();             dicLinkIndex = new Dictionary<TKey, LinkedListNode<TKey>>();             dicRefresh = new Dictionary<TKey, long>();             removeEntities = new BlockingCollection<RemoveEntity<TKey, TValue>>(1000);                         countTime();             RemoveNotice();         }

        /// <summary>         /// 換算時間;         /// 將秒轉換成ticks個數         /// </summary>         private void countTime()         {                         checkTicks = 10000000 * cacheTime;         }

        /// <summary>         /// 更新時間         /// </summary>         /// <param name="key"></param>         private void Refresh(TKey key)         {             dicRefresh[key] = DateTime.Now.Ticks;             if(!isCheckTime)             {                 return;             }             if(!isCheckThread)             {                 isCheckThread = true;                 Task.Factory.StartNew(() =>                 {                                       double wait = (DateTime.Now - checkTime).TotalSeconds;                     if(wait<cacheTime)                     {                         //如果上次監測到本次監測還未到設定的保持時間,                         //則等待該時間差後再檢查                         double sleep = ((double)cacheTime-wait) * 1000+1;                         Thread.Sleep((int)sleep);                     }                     locker.EnterWriteLock();                     try                     {                         LinkedListNode<TKey> last = null;                         long tick;                         long curTick = DateTime.Now.Ticks;                         last = linkedList.Last;//重後往前找                         while (last != null)                         {                             if (dicRefresh.TryGetValue(last.Value, out tick))                             {                                 if ((curTick - tick) > checkTicks)                                 {                                     dicLinkIndex.Remove(last.Value);                                     dicRefresh.Remove(last.Value);                                     linkedList.RemoveLast();                                     RemoveEntity<TKey, TValue> entity = new RemoveEntity<TKey, TValue>() { Key = last.Value, Value = dictionary[last.Value], RemoveType= RemoveType.TimeOut };                                     removeEntities.Add(entity);                                     dictionary.Remove(last.Value);                                 }                                 else                                 {                                     break;                                 }                             }                             last = linkedList.Last;                         }                     }                     finally { locker.ExitWriteLock(); }                     isCheckThread = false;                     checkTime = DateTime.Now;                 });             }         }

        private void RemoveNotice()         {             Task.Factory.StartNew(() =>             {                 while(true)                 {

                    RemoveEntity<TKey, TValue> item=null;                     if(removeEntities.TryTake(out item,500))                     {                         if(this.RemoveEntitiesEvent != null)                         {                             RemoveEntitiesEvent(CacheName, item);                         }                     }                 }             });         }

        public void Set(TKey key, TValue value)         {             locker.EnterWriteLock();             try             {                   dictionary[key] = value;                   LinkedListNode<TKey> item = null;                  if(dicLinkIndex.TryGetValue(key,out item))                 {                     linkedList.Remove(item);                 }                  dicLinkIndex[key]= linkedList.AddFirst(key);                                   if (linkedList.Count > _capacity)                 {                     dictionary.Remove(linkedList.Last.Value);                     dicLinkIndex.Remove(linkedList.Last.Value);                     linkedList.RemoveLast();                     dicRefresh.Remove(linkedList.Last.Value);                     RemoveEntity<TKey, TValue> entity = new RemoveEntity<TKey, TValue>() { Key = linkedList.Last.Value, Value = dictionary[linkedList.Last.Value], RemoveType = RemoveType.Capacity };                     removeEntities.Add(entity);                     dictionary.Remove(linkedList.Last.Value);                 }                 Refresh(key);             }             finally { locker.ExitWriteLock(); }                    }

        public bool TryGet(TKey key, out TValue value)         {             locker.EnterUpgradeableReadLock();             try             {                 bool b = dictionary.TryGetValue(key, out value);                 if (b)                 {                     locker.EnterWriteLock();                     try                     {                         linkedList.Remove(key);                         linkedList.AddFirst(key);                     }                     finally { locker.ExitWriteLock(); }

                }                 Refresh(key);                 return b;             }             catch { throw; }             finally { locker.ExitUpgradeableReadLock(); }         }         public void Clear()         {             locker.EnterWriteLock();             try             {                 dictionary.Clear();                 linkedList.Clear();                 dicRefresh.Clear();                 dicLinkIndex.Clear();                 dicRefresh.Clear();             }             finally             {                 locker.ExitWriteLock();             }         }         public bool Remove(TKey key)         {             bool isSucess = false;             locker.EnterWriteLock();             try             {                 isSucess = dictionary.Remove(key);                 dicRefresh.Remove(key);                 LinkedListNode<TKey> item = null;                 if (dicLinkIndex.TryGetValue(key, out item))                 {                     linkedList.Remove(item);                 }             }             finally             {                 locker.ExitWriteLock();             }             return isSucess;         }         public bool ContainsKey(TKey key)         {             locker.EnterReadLock();             try             {                 return dictionary.ContainsKey(key);             }             finally { locker.ExitReadLock(); }         }

        public int Count         {             get             {                 locker.EnterReadLock();                 try                 {                     return dictionary.Count;                 }                 finally { locker.ExitReadLock(); }             }         }

        public int Capacity         {             get             {                 locker.EnterReadLock();                 try                 {                     return _capacity;                 }                 finally { locker.ExitReadLock(); }             }             set             {                 locker.EnterUpgradeableReadLock();                 try                 {                     if (value > 0 && _capacity != value)                     {                         locker.EnterWriteLock();                         try                         {                             _capacity = value;                             while (linkedList.Count > _capacity)                             {                                 linkedList.RemoveLast();                             }                         }                         finally { locker.ExitWriteLock(); }                     }                 }                 finally { locker.ExitUpgradeableReadLock(); }             }         }

        public ICollection<TKey> Keys         {             get             {                 locker.EnterReadLock();                 try                 {                     return dictionary.Keys;                 }                 finally { locker.ExitReadLock(); }             }         }

        public ICollection<TValue> Values         {             get             {                 locker.EnterReadLock();                 try                 {                     return dictionary.Values;                 }                 finally { locker.ExitReadLock(); }             }         }     }

//最後在定一個異常的實體

public class RemoveEntity<TKey,TValue>     {         public TKey Key { get; set; }         public TValue Value { get; set; }

        public RemoveType RemoveType { get; set; }     }

就完成了,測試程式碼

             LRUCache<int, int> cache = new LRUCache<int, int>();               cache.RemoveEntitiesEvent += Cache_RemoveEntitiesEvent;               cache.CacheTime =3;//啟動快取時間              Random random = new Random();              DateTime start= DateTime.Now;             for(int i=0;i<10000000;i++)             {                 cache.Set(i,random.Next());                             }                         Console.WriteLine("時間:" + (DateTime.Now - start).TotalSeconds);             Console.Read();

  總共10-12秒;如果遮蔽快取時間設定,7秒

程式碼已經傳到GIT,地址和上一篇快取模板一直,整合在同一個專案中。