1:.NET Core 已經沒System.Web,也木有了HttpRuntime.Cache,所以,該空間下Cache也木有了。html
2:.NET Core 有新的Memory Cache提供,不過該內存類我看了一下,並無支持文件的緩存依賴。git
所以,在此前提下,預計.NET Core明年出來2.0版本時,可能也沒支持文件的緩存依賴,所以,有必要提早準備實現。github
在寫此文前,我掃了一下園子裏關於自定義緩存類的相關文章。緩存
發現不少自定義的緩存類文章都簡單停留在對字典的增刪改查。安全
所以,決定補充這一篇完整思路的。併發
下面,就介紹一下這個緩存類的實現過程及原理。函數
1:用static Dictionary<string,object> 來存檔。高併發
A:爲了處理併發,V4.0或以上,能夠用System.Collections.Concurrent.ConcurrentDictionary<string,object> 來存檔。性能
B:若是爲了支持.NET 2.0,則須要本身實現一個加鎖的字典(本文即此種狀況)測試
2:對該Dictionary提供增刪改查方法。
3:提供定時緩存的過時策略。
4:提供文件監控策略。
5:測試併發、性能、和內存佔用問題。
如下內容,重點介紹個人思路,源碼截圖以片段方式提供,具體的源碼,會在連接中。
若是要支持2.0,那麼就只能本身實現了:實現的思路也很簡單,只要對操做都加上鎖便可:
詳情源碼見:https://github.com/cyq1162/cyqdata/blob/master/Tool/MDictionary.cs
private MDictionary<string, object> theCache = new MDictionary<string, object>(2048, StringComparer.OrdinalIgnoreCase);//key,cache private MDictionary<string, DateTime> theKeyTime = new MDictionary<string, DateTime>(2048, StringComparer.OrdinalIgnoreCase);//key,time
有了theKeyTime,在每取get cache的時候,根據時間能夠判斷出,該Key是否是,若是已過時,則放棄。
可是有一個問題,若是緩存已通過期,但一直不被調用,那不是一直存在?
爲了解決這個問題,須要一個定時器,定時清理過時的Cache。
因爲Cache已經被設計成單例,所以能夠在構造函數啓動一個線程,來作定時任務清理過時的緩存。
定時遍歷theKeyTime,找到過時時間的Cache進行刪除。
由於遍歷期間集合不能修改或刪除,所以將遍歷的符合條件的存檔到新的對象,再統一處理新的對象去清除。
優勢:邏輯簡單。
缺點:遍歷的過程,緩存不能被修改,須要鎖住(緩存的對象越多,鎖住的時間越長),另外每次都要遍歷全部。
private SortedDictionary<int, MList<string>> theTime = new SortedDictionary<int, MList<string>>();//worktime,keylist
新增長了一個時間片字典,以固定的時間(如5分鐘)爲1個單位。
這樣全部緩存的時間就有序的分散在這些時間片上,定時器只要按節奏處理一個就能夠了。
每一個時間片都記錄全部的Key。
缺點:增長處理邏輯。
優勢:過時策略再也不有鎖,能快速直接定位過時數據並清除。
【一開始個人思路是List<key> keys來存檔全部key,移除的時候只移除key,而後其它交給定時器去清理。
因爲只考慮它是線程安全,結果作性能測試時,很明顯的發現問題】
List是鏈表實現,所以,隨着數據量的增長,Contains方法的性能會極速降低。
所以,須要簡單的處理一下解決性能問題,臨時折騰了個MList:
internal class MList<T> { List<T> list; Dictionary<T, int> dic; public MList() { list = new List<T>(); dic = new Dictionary<T, int>(); } public MList(int num) { list = new List<T>(num); dic = new Dictionary<T, int>(num); } public void Add(T key) { dic.Add(key, 0); list.Add(key); } public bool Contains(T key) { return dic.ContainsKey(key); } public void Remove(T key) { dic.Remove(key); list.Remove(key); } public void Clear() { dic.Clear(); list.Clear(); } public int Count { get { return list.Count; } } public List<T> GetList() { return list; } }
這個簡而言之,就是文件被修改的時候,如何使緩存自動過時。
我要支持這個策略的緣由:是由於Taurus.MVC,對View加載的html會被緩存在內存中的,當html被修改時,須要及時反應清掉緩存並從新加載。
private MDictionary<string, string> theFileName = new MDictionary<string, string>();//key,filename private MDictionary<string, FileSystemWatcher> theFolderWatcher = new MDictionary<string, FileSystemWatcher>();//folderPath,watch private MDictionary<string, MList<string>> theFolderKeys = new MDictionary<string, MList<string>>();//folderPath,keylist
重點講解:
1:用FileSystemWatcher來作文件監控(發現.NET Core里居然有支持這個類)
2:問題:一開始,也是想的很簡單,每個文件開一個監控就完事了,結果沒那麼簡單:
A:FileSystemWatcher對象太多,性能降低很快。 B:不一樣的Key指向同一個路徑問題。
3:解決:後來,想到監控是以文件夾爲單位,那麼經過文件夾來搞搞實現:
A:以文件夾爲單位:所以,文件對象便可以減小不少,提高性能問題。 B:以文件夾爲單位:能夠彙總對應的Keys,當文件變動時,能夠快速定位到文件。
一個緩存類寫好後,測試是少不了的,特別是併發,畢竟緩存是屬於高併發的操做。
所以,緩存哪些地方要加lock的,哪些能夠不加的,都須要仔細思考。
測試是經過的,就不截圖了。
性能測試,是經過和HttpRuntime.Cache作的比較。
100萬次的插入:
100萬次的移除:
暫無測試。
https://github.com/cyq1162/cyqdata/blob/master/Cache/LocalCache.cs
原本是計劃昨天就寫此文的,結果臨時開了培訓課,所以只能深夜來寫此文了。
關於培訓見:http://www.cnblogs.com/cyq1162/p/6097445.html
在培訓的過程,大夥都問怎麼提高技術?我答:造輪子。
另外,有人問我怎麼看.NET Core,還能怎麼看,拉好板凳,就等你了:.NET Core 2.0。
夜又深深,該入眠了~~~~