程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> ASP.NET Core 折騰筆記二:自己寫個完整的Cache緩存類來支持.NET Core,corecache

ASP.NET Core 折騰筆記二:自己寫個完整的Cache緩存類來支持.NET Core,corecache

編輯:關於.NET

ASP.NET Core 折騰筆記二:自己寫個完整的Cache緩存類來支持.NET Core,corecache


背景:

1:.NET Core 已經沒System.Web,也木有了HttpRuntime.Cache,因此,該空間下Cache也木有了。

2:.NET Core 有新的Memory Cache提供,不過該內存類我看了一下,並沒有支持文件的緩存依賴。

因此,在此前提下,預計.NET Core明年出來2.0版本時,可能也沒支持文件的緩存依賴,因此,有必要提前准備實現。

在寫此文前,我掃了一下園子裡關於自定義緩存類的相關文章。

發現很多自定義的緩存類文章都簡單停留在對字典的增刪改查。

因此,決定補充這一篇完整思路的。

下面,就介紹一下這個緩存類的實現過程及原理。

實現緩存的類的核心思路介紹:

1:用static Dictionary<string,object> 來存檔。

A:為了處理並發,V4.0或以上,可以用System.Collections.Concurrent.ConcurrentDictionary<string,object> 來存檔。

B:如果為了支持.NET 2.0,則需要自己實現一個加鎖的字典(本文即此種情況)

2:對該Dictionary提供增刪改查方法。

3:提供定時緩存的過期策略。

4:提供文件監控策略。

5:測試並發、性能、和內存占用問題。

以下內容,重點介紹我的思路,源碼截圖以片斷方式提供,具體的源碼,會在鏈接中。

1:自定義線程安全的MDictionary(支持.NET 2.0)

如果要支持2.0,那麼就只能自己實現了:實現的思路也很簡單,只要對操作都加上鎖即可:

詳情源碼見:https://github.com/cyq1162/cyqdata/blob/master/Tool/MDictionary.cs

2:時間過期策略:

 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。

缺點:增加處理邏輯。

優點:過期策略不再有鎖,能快速直接定位過期數據並清除。

3:關於List的性能

【一開始我的思路是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;
        }
    }

4:文件緩存依賴策略:

這個簡而言之,就是文件被修改的時候,如何使緩存自動過期。

我要支持這個策略的原因:是因為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,當文件變更時,可以快速定位到文件。

5:並發:

一個緩存類寫好後,測試是少不了的,特別是並發,畢竟緩存是屬於高並發的操作。

因此,緩存哪些地方要加lock的,哪些可以不加的,都需要仔細思考。

測試是通過的,就不截圖了。

6:性能:

性能測試,是通過和HttpRuntime.Cache做的比較。

100萬次的插入:

100萬次的移除:

7:占用內存:

暫無測試。

詳細源碼:

https://github.com/cyq1162/cyqdata/blob/master/Cache/LocalCache.cs

總結:

本來是計劃昨天就寫此文的,結果臨時開了培訓課,因此只能深夜來寫此文了。

關於培訓見:http://www.cnblogs.com/cyq1162/p/6097445.html

在培訓的過程,大伙都問怎麼提升技術?我答:造輪子。

另外,有人問我怎麼看.NET Core,還能怎麼看,拉好板凳,就等你了:.NET Core 2.0。

夜又深深,該入眠了~~~~

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved