日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一步步实现一个基本的缓存模块

發布時間:2025/3/13 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一步步实现一个基本的缓存模块 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一步步實現一個基本的緩存模塊

注意后續代碼及改進見后后文及github,文章上的并沒有更新。

??? 1. 前言
??? 2.? 請求級別緩存
??? 2.1 多線程
??? 3.? 進程級別緩存
??? 3.1 分區與計數
??? 3.2 可空緩存值
??? 3.3 封裝與集成
??? 4.? 小結

1. 前言

  • 面向讀者:初、中級用戶;
  • 涉及知識:HttpContext、HttpRuime.Cache、DictionaryEntry、Unit Test等;
  • 文章目的:這里的內容不會涉及 Memcached、Redies 等進程外緩存的使用,只針對包含WEB應用的常見場景,實現一個具有線程安全、分區、過期特性的緩存模塊,略微提及DI等內容。
  • jusfr 原創,轉載請注明來自博客園。


2.? 請求級別緩存

如果需要線程安全地存取數據,System.Collections.Concurrent 命名空間下的像 ConcurrentDictionary 等實現是首選;更復雜的特性像過期策略、文件依賴等就需要其他實現了。ASP.NET中的HttpContext.Current.Items 常常被用作自定義數據容器,注入工具像Unity、Autofac 等便借助自定義 HttpModule 將容器掛接在 HttpContext.Current 上以進行生命周期管理。

基本接口 ICacheProvider,請求級別的緩存從它定義,考慮到請求級別緩存的運用場景有限,故只定義有限特性;

1 public interface ICacheProvider { 2 Boolean TryGet<T>(String key, out T value); 3 T GetOrCreate<T>(String key, Func<T> function); 4 T GetOrCreate<T>(String key, Func<String, T> factory); 5 void Overwrite<T>(String key, T value); 6 void Expire(String key); 7 }

HttpContext.Current.Items 從 IDictionary 定義,存儲 Object-Object 鍵值對,出于便利與直觀,ICacheProvider 只接受String類型緩存鍵,故HttpContextCacheProvider內部使用 BuildCacheKey(String key) 方法生成真正緩存鍵以避免鍵值重復;

同時 HashTable 可以存儲空引用作為緩存值,故 TryGet() 方法先進行 Contains() 判斷存在與否,再進行類型判斷,避免緩存鍵重復使用;??

1 public class HttpContextCacheProvider : ICacheProvider { 2 protected virtual String BuildCacheKey(String key) { 3 return String.Concat("HttpContextCacheProvider_", key); 4 } 5 6 public Boolean TryGet<T>(String key, out T value) { 7 key = BuildCacheKey(key); 8 Boolean exist = false; 9 if (HttpContext.Current.Items.Contains(key)) { 10 exist = true; 11 Object entry = HttpContext.Current.Items[key]; 12 if (entry != null && !(entry is T)) { 13 throw new InvalidOperationException(String.Format("緩存項`[{0}]`類型錯誤, {1} or {2} ?", 14 key, entry.GetType().FullName, typeof(T).FullName)); 15 } 16 value = (T)entry; 17 } 18 else { 19 value = default(T); 20 } 21 return exist; 22 } 23 24 public T GetOrCreate<T>(String key, Func<T> function) { 25 T value; 26 if (TryGet(key, out value)) { 27 return value; 28 } 29 value = function(); 30 Overwrite(key, value); 31 return value; 32 } 33 34 public T GetOrCreate<T>(String key, Func<String, T> factory) { 35 T value; 36 if (TryGet(key, out value)) { 37 return value; 38 } 39 value = factory(key); 40 Overwrite(key, value); 41 return value; 42 } 43 44 public void Overwrite<T>(String key, T value) { 45 key = BuildCacheKey(key); 46 HttpContext.Current.Items[key] = value; 47 } 48 49 public void Expire(String key) { 50 key = BuildCacheKey(key); 51 HttpContext.Current.Items.Remove(key); 52 } 53 }

這里使用了 Func<T> 委托的運用,合并查詢、判斷和添加緩存項的操作以簡化接口調用;如果用戶期望不同類型緩存值可以存儲到相同的 key 上,則需要重新定義 BuildCacheKey() 方法將緩存值類型作為參數參與生成緩存鍵,此時 Expire() 方法則同樣需要了。測試用例:

1 [TestClass] 2 public class HttpContextCacheProviderTest { 3 [TestInitialize] 4 public void Initialize() { 5 HttpContext.Current = new HttpContext(new HttpRequest(null, "http://localhost", null), new HttpResponse(null)); 6 } 7 8 [TestMethod] 9 public void NullValue() { 10 var key = "key-null"; 11 HttpContext.Current.Items.Add(key, null); 12 Assert.IsTrue(HttpContext.Current.Items.Contains(key)); 13 Assert.IsNull(HttpContext.Current.Items[key]); 14 } 15 16 [TestMethod] 17 public void ValueType() { 18 var key = "key-guid"; 19 ICacheProvider cache = new HttpContextCacheProvider(); 20 var id1 = Guid.NewGuid(); 21 var id2 = cache.GetOrCreate(key, () => id1); 22 Assert.AreEqual(id1, id2); 23 24 cache.Expire(key); 25 Guid id3; 26 var exist = cache.TryGet(key, out id3); 27 Assert.IsFalse(exist); 28 Assert.AreNotEqual(id1, id3); 29 Assert.AreEqual(id3, Guid.Empty); 30 } 31 } View Code

引用類型測試用例忽略。


2.1 多線程

異步等情況下,HttpContext.Current并非無處不在,故異步等情況下 HttpContextCacheProvider 的使用可能拋出空引用異常,需要被處理,對此園友有過思考 ,這里貼上A大的方案 ,有需求的讀者請按圖索驥。

3.? 進程級別緩存

HttpRuntime.Cache 定義在 System.Web.dll 中,System.Web 命名空間下,實際上是可以使用在非 Asp.Net 應用里的;另外 HttpContext 對象包含一個 Cache 屬性,它們的關系可以閱讀 HttpContext.Cache 和 HttpRuntime.Cache;

HttpRuntime.Cache 為 System.Web.Caching.Cache 類型,支持滑動/絕對時間過期策略、支持緩存優先級、緩存更新/過期回調、基于文件的緩存依賴項等,功能十分強大,這里借用少數特性來實現進程級別緩存,更多文檔請自行檢索。

從 ICacheProvider 定義 IHttpRuntimeCacheProvider,添加相對過期與絕對過期、添加批量的緩存過期接口 ExpireAll();

1 public interface IHttpRuntimeCacheProvider : ICacheProvider { 2 T GetOrCreate<T>(String key, Func<T> function, TimeSpan slidingExpiration); 3 T GetOrCreate<T>(String key, Func<T> function, DateTime absoluteExpiration); 4 void Overwrite<T>(String key, T value, TimeSpan slidingExpiration); 5 void Overwrite<T>(String key, T value, DateTime absoluteExpiration); 6 void ExpireAll(); 7 }

System.Web.Caching.Cache 只繼承 IEnumerable,內部使用 DictionaryEntry 存儲Object-Object 鍵值對,但 HttpRuntime.Cache 只授受字符串類型緩存鍵及非空緩存值,關于空引用緩存值的問題,我們在3.2中討論;

故 TryGet() 與 HttpContextCacheProvider.TryGet() 具有顯著差異,前者需要拿出值來進行非空判斷,后者則是使用 IDictionary.Contains() 方法;

除了 TryGet() 方法與過期過期參數外的差異外,接口實現與 HttpContextCacheProvider 類似;

1 public class HttpRuntimeCacheProvider : IHttpRuntimeCacheProvider { 2 private static readonly Object _sync = new Object(); 3 4 protected virtual String BuildCacheKey(String key) { 5 return String.Concat("HttpRuntimeCacheProvider_", key); 6 } 7 8 public Boolean TryGet<T>(String key, out T value) { 9 key = BuildCacheKey(key); 10 Boolean exist = false; 11 Object entry = HttpRuntime.Cache.Get(key); 12 if (entry != null) { 13 exist = true; 14 if (!(entry is T)) { 15 throw new InvalidOperationException(String.Format("緩存項[{0}]類型錯誤, {1} or {2} ?", 16 key, entry.GetType().FullName, typeof(T).FullName)); 17 } 18 value = (T)entry; 19 } 20 else { 21 value = default(T); 22 } 23 return exist; 24 } 25 26 public T GetOrCreate<T>(String key, Func<String, T> factory) { 27 T result; 28 if (TryGet<T>(key, out result)) { 29 return result; 30 } 31 result = factory(key); 32 Overwrite(key, result); 33 return result; 34 } 35 36 public T GetOrCreate<T>(String key, Func<T> function) { 37 T result; 38 if (TryGet<T>(key, out result)) { 39 return result; 40 } 41 result = function(); 42 Overwrite(key, result); 43 return result; 44 } 45 46 47 public T GetOrCreate<T>(String key, Func<T> function, TimeSpan slidingExpiration) { 48 T result; 49 if (TryGet<T>(key, out result)) { 50 return result; 51 } 52 result = function(); 53 Overwrite(key, result, slidingExpiration); 54 return result; 55 } 56 57 public T GetOrCreate<T>(String key, Func<T> function, DateTime absoluteExpiration) { 58 T result; 59 if (TryGet<T>(key, out result)) { 60 return result; 61 } 62 result = function(); 63 Overwrite(key, result, absoluteExpiration); 64 return result; 65 } 66 67 public void Overwrite<T>(String key, T value) { 68 HttpRuntime.Cache.Insert(BuildCacheKey(key), value); 69 } 70 71 //slidingExpiration 時間內無訪問則過期 72 public void Overwrite<T>(String key, T value, TimeSpan slidingExpiration) { 73 HttpRuntime.Cache.Insert(BuildCacheKey(key), value, null, 74 Cache.NoAbsoluteExpiration, slidingExpiration); 75 } 76 77 //absoluteExpiration 絕對時間過期 78 public void Overwrite<T>(String key, T value, DateTime absoluteExpiration) { 79 HttpRuntime.Cache.Insert(BuildCacheKey(key), value, null, 80 absoluteExpiration, Cache.NoSlidingExpiration); 81 } 82 83 public void Expire(String key) { 84 HttpRuntime.Cache.Remove(BuildCacheKey(key)); 85 } 86 87 public void ExpireAll() { 88 lock (_sync) { 89 var entries = HttpRuntime.Cache.OfType<DictionaryEntry>() 90 .Where(entry => (entry.Key is String) && ((String)entry.Key).StartsWith("HttpRuntimeCacheProvider_")); 91 foreach (var entry in entries) { 92 HttpRuntime.Cache.Remove((String)entry.Key); 93 } 94 } 95 } 96 }

測試用例與 HttpContextCacheProviderTest 類似,這里貼出緩存過期的測試:??

1 public class HttpRuntimeCacheProviderTest { 2 [TestMethod] 3 public void GetOrCreateWithAbsoluteExpirationTest() { 4 var key = Guid.NewGuid().ToString(); 5 var val = Guid.NewGuid(); 6 7 IHttpRuntimeCacheProvider cacheProvider = new HttpRuntimeCacheProvider(); 8 var result = cacheProvider.GetOrCreate<Guid>(key, () => val, DateTime.UtcNow.AddSeconds(2D)); 9 Assert.AreEqual(result, val); 10 11 var exist = cacheProvider.TryGet<Guid>(key, out val); 12 Assert.IsTrue(exist); 13 Assert.AreEqual(result, val); 14 15 Thread.Sleep(2000); 16 exist = cacheProvider.TryGet<Guid>(key, out val); 17 Assert.IsFalse(exist); 18 Assert.AreEqual(val, Guid.Empty); 19 } 20 21 [TestMethod] 22 public void ExpireAllTest() { 23 var key = Guid.NewGuid().ToString(); 24 var val = Guid.NewGuid(); 25 26 IHttpRuntimeCacheProvider cacheProvider = new HttpRuntimeCacheProvider(); 27 var result = cacheProvider.GetOrCreate<Guid>(key, () => val); 28 Assert.AreEqual(result, val); 29 30 cacheProvider.ExpireAll(); 31 Guid val2; 32 var exist = cacheProvider.TryGet<Guid>(key, out val2); 33 Assert.IsFalse(exist); 34 Assert.AreEqual(val2, Guid.Empty); 35 } 36 } View Code

3.1 分區與計數

緩存分區是常見需求,緩存用戶A、用戶B的認證信息可以拿用戶標識作為緩存鍵,但每個用戶分別有一整套包含授權的其他數據時,為創建以用戶分區的緩存應該是更好的選擇;
常規的想法是為緩存添加類似 `Region` 或 `Partition`的參數,個人覺得這不是很好的實踐,因為接口被修改,同時過多的參數非常讓人困惑;

讀者可能對前文中 BuildCacheKey() 方法被 protected virtual 修飾覺得很奇怪,是的,個人覺得定義新的接口,配合從緩存Key的生成算法作文章來分區貌似比較巧妙,也迎合依賴注冊被被廣泛使用的現狀;

分區的進程級別緩存定義,只需多出一個屬性:

1 public interface IHttpRuntimeRegionCacheProvider : IHttpRuntimeCacheProvider { 2 String Region { get; } 3 }

分區的緩存實現,先為 IHttpRuntimeCacheProvider 添加計數,然后重構HttpRuntimeCacheProvider,提取出過濾算法,接著重寫 BuildCacheKey() 方法的實現,使不同分區的生成不同的緩存鍵,緩存項操作方法無須修改;??

1 public interface IHttpRuntimeCacheProvider : ICacheProvider { 2 ... 3 Int32 Count { get; } 4 } 5 6 public class HttpRuntimeCacheProvider : IHttpRuntimeCacheProvider { 7 ... 8 protected virtual Boolean Hit(DictionaryEntry entry) { 9 return (entry.Key is String) && ((String)entry.Key).StartsWith("HttpRuntimeCacheProvider_"); 10 } 11 12 public void ExpireAll() { 13 lock (_sync) { 14 var entries = HttpRuntime.Cache.OfType<DictionaryEntry>().Where(Hit); 15 foreach (var entry in entries) { 16 HttpRuntime.Cache.Remove((String)entry.Key); 17 } 18 } 19 } 20 21 public Int32 Count { 22 get { 23 lock (_sync) { 24 return HttpRuntime.Cache.OfType<DictionaryEntry>().Where(Hit).Count(); 25 } 26 } 27 } 28 } 29 30 public class HttpRuntimeRegionCacheProvider : HttpRuntimeCacheProvider, IHttpRuntimeRegionCacheProvider { 31 private String _prefix; 32 public virtual String Region { get; private set; } 33 34 private String GetPrifix() { 35 if (_prefix == null) { 36 _prefix = String.Concat("HttpRuntimeRegionCacheProvider_", Region, "_"); 37 } 38 return _prefix; 39 } 40 41 public HttpRuntimeRegionCacheProvider(String region) { 42 Region = region; 43 } 44 45 protected override String BuildCacheKey(String key) { 46 //Region 為空將被當作 String.Empty 處理 47 return String.Concat(GetPrifix(), base.BuildCacheKey(key)); 48 } 49 50 protected override Boolean Hit(DictionaryEntry entry) { 51 return (entry.Key is String) && ((String)entry.Key).StartsWith(GetPrifix()); 52 } 53 }

測試用例示例了兩個分區緩存對相同 key 的操作:?

1 [TestClass] 2 public class HttpRuntimeRegionCacheProviderTest { 3 [TestMethod] 4 public void ValueType() { 5 var key = "key-guid"; 6 IHttpRuntimeCacheProvider cache1 = new HttpRuntimeRegionCacheProvider("Region1"); 7 var id1 = cache1.GetOrCreate(key, Guid.NewGuid); 8 9 IHttpRuntimeCacheProvider cache2 = new HttpRuntimeRegionCacheProvider("Region2"); 10 var id2 = cache2.GetOrCreate(key, Guid.NewGuid); 11 Assert.AreNotEqual(id1, id2); 12 13 cache1.ExpireAll(); 14 Assert.AreEqual(cache1.Count, 0); 15 Assert.AreEqual(cache2.Count, 1); 16 } 17 } View Code

至此一個基本的緩存模塊已經完成;

3.2 可空緩存值

前文提及過,HttpRuntime.Cache 不授受空引用作為緩存值,與 HttpContext.Current.Items表現不同,另一方面實際需求中,空值作為字典的值仍然是有意義,此處給出一個支持空緩存值的實現;

HttpRuntime.Cache 斷然是不能把 null 存入的,查看 HttpRuntimeCacheProvider.TryGet() 方法,可知 HttpRuntime.Cache.Get() 獲取的總是 Object 類型,思路可以這樣展開:

1) 添加緩存時進行判斷,如果非空,常規處理,否則把用一個特定的自定義對象存入;
2) 取出緩存時進行判斷,如果為特定的自定義對象,返回 null;

為 HttpRuntimeCacheProvider 的構造函數添加可選參數,TryGet() 加入 null 判斷邏輯;添加方法 BuildCacheEntry(),替換空的緩存值為 _nullEntry,其他方法不變;??

1 public class HttpRuntimeCacheProvider : IHttpRuntimeCacheProvider { 2 private static readonly Object _sync = new Object(); 3 private static readonly Object _nullEntry = new Object(); 4 private Boolean _supportNull; 5 6 public HttpRuntimeCacheProvider(Boolean supportNull = false) { 7 _supportNull = supportNull; 8 } 9 10 protected virtual String BuildCacheKey(String key) { 11 return String.Concat("HttpRuntimeCacheProvider_", key); 12 } 13 14 protected virtual Object BuildCacheEntry<T>(T value) { 15 Object entry = value; 16 if (value == null) { 17 if (_supportNull) { 18 entry = _nullEntry; 19 } 20 else { 21 throw new InvalidOperationException(String.Format("Null cache item not supported, try ctor with paramter 'supportNull = true' ")); 22 } 23 } 24 return entry; 25 } 26 27 public Boolean TryGet<T>(String key, out T value) { 28 Object entry = HttpRuntime.Cache.Get(BuildCacheKey(key)); 29 Boolean exist = false; 30 if (entry != null) { 31 exist = true; 32 if (!(entry is T)) { 33 if (_supportNull && !(entry == _nullEntry)) { 34 throw new InvalidOperationException(String.Format("緩存項`[{0}]`類型錯誤, {1} or {2} ?", 35 key, entry.GetType().FullName, typeof(T).FullName)); 36 } 37 value = (T)((Object)null); 38 } 39 else { 40 value = (T)entry; 41 } 42 } 43 else { 44 value = default(T); 45 } 46 return exist; 47 } 48 49 public T GetOrCreate<T>(String key, Func<String, T> factory) { 50 T value; 51 if (TryGet<T>(key, out value)) { 52 return value; 53 } 54 value = factory(key); 55 Overwrite(key, value); 56 return value; 57 } 58 59 public T GetOrCreate<T>(String key, Func<T> function) { 60 T value; 61 if (TryGet<T>(key, out value)) { 62 return value; 63 } 64 value = function(); 65 Overwrite(key, value); 66 return value; 67 } 68 69 public T GetOrCreate<T>(String key, Func<T> function, TimeSpan slidingExpiration) { 70 T value; 71 if (TryGet<T>(key, out value)) { 72 return value; 73 } 74 value = function(); 75 Overwrite(key, value, slidingExpiration); 76 return value; 77 } 78 79 public T GetOrCreate<T>(String key, Func<T> function, DateTime absoluteExpiration) { 80 T value; 81 if (TryGet<T>(key, out value)) { 82 return value; 83 } 84 value = function(); 85 Overwrite(key, value, absoluteExpiration); 86 return value; 87 } 88 89 public void Overwrite<T>(String key, T value) { 90 HttpRuntime.Cache.Insert(BuildCacheKey(key), BuildCacheEntry<T>(value)); 91 } 92 93 //slidingExpiration 時間內無訪問則過期 94 public void Overwrite<T>(String key, T value, TimeSpan slidingExpiration) { 95 HttpRuntime.Cache.Insert(BuildCacheKey(key), BuildCacheEntry<T>(value), null, 96 Cache.NoAbsoluteExpiration, slidingExpiration); 97 } 98 99 //absoluteExpiration 時過期 100 public void Overwrite<T>(String key, T value, DateTime absoluteExpiration) { 101 HttpRuntime.Cache.Insert(BuildCacheKey(key), BuildCacheEntry<T>(value), null, 102 absoluteExpiration, Cache.NoSlidingExpiration); 103 } 104 105 public void Expire(String key) { 106 HttpRuntime.Cache.Remove(BuildCacheKey(key)); 107 } 108 109 protected virtual Boolean Hit(DictionaryEntry entry) { 110 return (entry.Key is String) && ((String)entry.Key).StartsWith("HttpRuntimeCacheProvider_"); 111 } 112 113 public void ExpireAll() { 114 lock (_sync) { 115 var entries = HttpRuntime.Cache.OfType<DictionaryEntry>().Where(Hit); 116 foreach (var entry in entries) { 117 HttpRuntime.Cache.Remove((String)entry.Key); 118 } 119 } 120 } 121 122 public Int32 Count { 123 get { 124 lock (_sync) { 125 return HttpRuntime.Cache.OfType<DictionaryEntry>().Where(Hit).Count(); 126 } 127 } 128 } 129 }

然后是分區緩存需要修改構造函數:

1 public HttpRuntimeRegionCacheProvider(String region) 2 : base(false) { 3 Region = region; 4 } 5 6 public HttpRuntimeRegionCacheProvider(String region, Boolean supportNull) 7 : base(supportNull) { 8 Region = region; 9 } 10 ... 11 }

測試用例:?

1 [TestClass] 2 public class HttpRuntimeCacheProviderTest { 3 [TestMethod] 4 public void NullCacheErrorTest() { 5 var key = "key-null"; 6 Person person = null; 7 IHttpRuntimeCacheProvider cacheProvider = new HttpRuntimeCacheProvider(false); 8 try { 9 cacheProvider.GetOrCreate<Person>(key, () => person); //error 10 Assert.Fail(); 11 } 12 catch (Exception ex) { 13 Assert.IsTrue(ex is InvalidOperationException); 14 } 15 16 Person person2; 17 var exist = cacheProvider.TryGet(key, out person2); 18 Assert.IsFalse(exist); 19 Assert.AreEqual(person2, null); 20 } 21 22 [TestMethod] 23 public void NullableCacheTest() { 24 var key = "key-nullable"; 25 Person person = null; 26 IHttpRuntimeCacheProvider cacheProvider = new HttpRuntimeCacheProvider(true); 27 cacheProvider.GetOrCreate<Person>(key, () => person); 28 Person person2; 29 var exist = cacheProvider.TryGet(key, out person2); 30 Assert.IsTrue(exist); 31 Assert.AreEqual(person2, null); 32 } 33 34 class Person { 35 public Int32 Id { get; set; } 36 public String Name { get; set; } 37 } 38 } View Code

3.3 封裝與集成

多數情況下我們不需要暴露實現和手動創建上文所提各種 CacheProvider,實踐中它們被 internal 修飾,再配合工廠類使用:??

1 public static class CacheProviderFacotry { 2 public static ICacheProvider GetHttpContextCache() { 3 return new HttpContextCacheProvider(); 4 } 5 6 public static IHttpRuntimeCacheProvider GetHttpRuntimeCache(Boolean supportNull = false) { 7 return new HttpRuntimeCacheProvider(supportNull); 8 } 9 10 public static IHttpRuntimeRegionCacheProvider GetHttpRuntimeRegionCache(String region, Boolean supportNull = false) { 11 return new HttpRuntimeRegionCacheProvider(region, supportNull); 12 } 13 14 public static IHttpRuntimeRegionCacheProvider Region(this IHttpRuntimeCacheProvider runtimeCacheProvider, String region, Boolean supportNull = false) { 15 return GetHttpRuntimeRegionCache(region, supportNull); 16 } 17 }

然后在依賴注入中的聲明如下,這里是 Autofac 下的組件注冊:?????

1 ... 2 //請求級別緩存, 使用 HttpContext.Current.Items 作為容器 3 builder.Register(ctx => CacheProviderFacotry.GetHttpContextCache()).As<ICacheProvider>().InstancePerLifetimeScope(); 4 //進程級別緩存, 使用 HttpRuntime.Cache 作為容器 5 builder.RegisterInstance(CacheProviderFacotry.GetHttpRuntimeCache()).As<IRuntimeCacheProvider>().ExternallyOwned(); 6 //進程級別且隔離的緩存, 若出于key算法唯一考慮而希望加入上下文件信息, 則仍然需要 CacheModule 類的實現 7 builder.Register(ctx => CacheProviderFacotry.GetHttpRuntimeRegionCache(/*... 分區依據 ...*/)) 8 .As<IRuntimeRegionCacheProvider>().InstancePerLifetimeScope(); 9 ...

4. 小結

本文簡單探討了一個具有線程安全、分區、過期特性緩存模塊的實現過程,只使用了HttpRuntime.Cache的有限特性,有更多需求的同學可以自行擴展;見解有限,謬誤之處還請園友指正。

園友Jusfr 原創,轉載請注明來自博客園? 。

注意后續代碼及改進見后后文及github,文章上的并沒有更新。

轉載于:https://www.cnblogs.com/Jusfr/p/4150954.html

總結

以上是生活随笔為你收集整理的一步步实现一个基本的缓存模块的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。