在完成了DNS解析模塊之后,我意識到了DNS緩存機制也很有必要。在Redis,Memcache,和.Net自帶的Cache之間,考慮到部署問題,最終選擇了后者,之前在學習Web及開發的過程中用過System.Web.Caching.Cache這個類庫,但是這次的爬蟲程序我打算部署為桌面軟件,所以選用了System.Runtime.Caching.MemoryCache(后期如有必要也會加入System.Web.Caching.Cache來適配Web端程序)。
MemoryCache的使用網上介紹的不多,不過這個是.NET4.0新引入的緩存對象,估計主要是替換原來企業庫的緩存模塊,使得.NET的緩存可以無處不在,而不用基於特定的Windows版本上使用。
出於方便考慮,我們將不再實例化新的MemoryCache對象,只對MemoryCache的默認示例Memory.Default進行增刪查操作。
基礎篇
增加:
增加緩存需要提供兩個參數,CacheItem類表示緩存中的單個緩存項,
構造函數:
CacheItem(String, Object, String) 用緩存項的指定鍵、值和區域初始化新的 CacheItem 實例。三個參數分別為:鍵、值和區域。
CacheItemPolicy類則表示緩存項的過期信息,只含有默認的構造函數。
增加一條緩存:
var item = new CacheItem("習大大", "兩學一做"); var policy = new CacheItemPolicy(); policy.SlidingExpiration = new TimeSpan(500); //插入一條key為"習大大",value為"兩學一做",500毫秒后自動銷毀的緩存 MemoryCache.Default.Add(item, policy); //重新設置policy的過期時間為當前時間+十分鍾 policy.AbsoluteExpiration = DateTimeOffset.Now + TimeSpan.FromMinutes(10); //注意,如果要使用Sliding時間,則Absolute必須為DateTimeOffset.MaxValue,反之,則Sliding必須為TimeSpan.Zero policy.SlidingExpiration = TimeSpan.Zero; //重新插入,覆蓋前一條數據 MemoryCache.Default.Add(item, policy);注意,如果要使用Sliding時間,則Absolute必須為DateTimeOffset.MaxValue,反之,則Sliding必須為TimeSpan.Zero
查詢:
緩存對象類似於字典集,查詢可以直接采用memoryCache[key]來進行,例如我們查詢一下前面插入的那條數據:
var idea = MemoryCache.Default["習大大"];
移除:
參數
key:要移除的緩存項的唯一標識符。 regionName:緩存中的一個添加了緩存項的命名區域。不要為該參數傳遞值。默認情況下,此參數為 null,因為 MemoryCache 類未實現區域。返回值
Type: System.Object 如果在緩存中找到該項,則為已移除的緩存項;否則為 null。
刪除前面加入的那一項:
MemoryCache.Default.Remove("習大大");
進階篇
明白了基本的用法之后,我們就可以對它做進一步的封裝,使之使用起來更為便捷:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Caching; namespace Crawler.Common { /// <summary> /// 基於MemoryCache的緩存輔助類 /// </summary> public static class MemoryCacheHelper { private static readonly object _locker = new object(); public static bool Contains(string key) { return MemoryCache.Default.Contains(key); } /// <summary> /// 獲取Catch元素 /// </summary> /// <typeparam name="T">所獲取的元素的類型</typeparam> /// <param name="key">元素的鍵</param> /// <returns>特定的元素值</returns> public static T Get<T>(string key) { if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("不合法的key!"); if (!MemoryCache.Default.Contains(key)) throw new ArgumentException("獲取失敗,不存在該key!"); if (!(MemoryCache.Default[key] is T)) throw new ArgumentException("未找到所需類型數據!"); return (T)MemoryCache.Default[key]; } /// <summary> /// 添加Catch元素 /// </summary> /// <param name="key">元素的鍵</param> /// <param name="value">元素的值</param> /// <param name="slidingExpiration">元素過期時間(時間間隔)</param> /// <param name="absoluteExpiration">元素過期時間(絕對時間)</param> /// <returns></returns> public static bool Add(string key, object value, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null) { var item = new CacheItem(key, value); var policy = CreatePolicy(slidingExpiration, absoluteExpiration); lock (_locker) return MemoryCache.Default.Add(item, policy); } /// <summary> /// 移出Cache元素 /// </summary> /// <typeparam name="T">待移出元素的類型</typeparam> /// <param name="key">待移除元素的鍵</param> /// <returns>已經移出的元素</returns> public static T Remove<T>(string key) { if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("不合法的key!"); if (!MemoryCache.Default.Contains(key)) throw new ArgumentException("獲取失敗,不存在該key!"); var value = MemoryCache.Default.Get(key); if (!(value is T)) throw new ArgumentException("未找到所需類型數據!"); return (T)MemoryCache.Default.Remove(key); } /// <summary> /// 移出多條緩存數據,默認為所有緩存 /// </summary> /// <typeparam name="T">待移出的緩存類型</typeparam> /// <param name="keyList"></param> /// <returns></returns> public static List<T> RemoveAll<T>(IEnumerable<string> keyList = null) { if (keyList != null) return (from key in keyList where MemoryCache.Default.Contains(key) where MemoryCache.Default.Get(key) is T select (T)MemoryCache.Default.Remove(key)).ToList(); while (MemoryCache.Default.GetCount() > 0) MemoryCache.Default.Remove(MemoryCache.Default.ElementAt(0).Key); return new List<T>(); } /// <summary> /// 設置過期信息 /// </summary> /// <param name="slidingExpiration"></param> /// <param name="absoluteExpiration"></param> /// <returns></returns> private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration) { var policy = new CacheItemPolicy(); if (absoluteExpiration.HasValue) { policy.AbsoluteExpiration = absoluteExpiration.Value; } else if (slidingExpiration.HasValue) { policy.SlidingExpiration = slidingExpiration.Value; } policy.Priority = CacheItemPriority.Default; return policy; } } }