功能要求
使用C#編寫一個鍵值結構進程內緩存,實現數據緩存的基本操作。 這里用到的知識點如下:
-值緩存實現
說明:這里創建一個基于.net 6平臺的控制臺項目。
導入命名空間()
using?System;
using?System.Collections.Concurrent;
using?System.Collections.Generic;
using?System.Threading;
using?System.Threading.Tasks;
在.cs類中編寫實現方法
///?
///?自定義內存緩存助手
///?
public?sealed?class?CustomCacheHelper
{
????#region?單例模式
????//創建私有化靜態obj鎖??
????private?static?readonly?object?_ObjLock?=?new();
????//創建私有靜態字段,接收類的實例化對象??
????private?static?volatile?CustomCacheHelper??_Instance?=?null;
????//構造函數私有化??
????private?CustomCacheHelper()?{?}
????//創建單利對象資源并返回??
????public?static?CustomCacheHelper?GetSingleObj()
????{
????????if?(_Instance?==?null)
????????{
????????????lock?(_ObjLock)
????????????{
????????????????if?(_Instance?==?null)
????????????????{
????????????????????_Instance?=?new?CustomCacheHelper();
????????????????}
????????????}
????????}
????????return?_Instance;
????}
????#endregion
????///?
????///?緩存字典?=>?【key|value|time】
????///?
????private?static?volatile?ConcurrentDictionary<string,?KeyValuePair<object,?DateTime?>>?_CacheDictionary?=?new();
????///?
????///?1.主動過期
????///?
????static?CustomCacheHelper()
????{
????????Task.Run(()?=>?{
????????????while?(true)
????????????{
????????????????int?millisecondsTimeout?=?1000?*?60?*?10;
????????????????Thread.Sleep(millisecondsTimeout);?//10分鐘檢查一次
????????????????if?(_CacheDictionary?!=?null?&&?_CacheDictionary.Keys.Count?>?0)
????????????????{
????????????????????ICollection<string>?listKey?=?_CacheDictionary.Keys;
????????????????????foreach?(var?key?in?listKey)
????????????????????{
????????????????????????var?valueTime?=?_CacheDictionary[key];
????????????????????????if?(valueTime.Value?????????????????????????{
????????????????????????????_CacheDictionary.TryRemove(key,?out?KeyValuePair<object,?DateTime?>?value);
????????????????????????}
????????????????????}
????????????????}
????????????}
????????});
????}
????///?
????///?索引器
????///?
????///?
????///?
????public?object?this[string?key]
????{
????????get?=>?_CacheDictionary[key];
????????set?=>?_CacheDictionary[key]?=?new?KeyValuePair<object,?DateTime?>(value,?null);
????}
????///?
????///?設置相對過期緩存
????///?
????///?鍵
????///?數據包
????///?相對過期時間
????public?void?Set(string?key,?object?data,?int?seconds)
????{
????????var?expirationTime?=?DateTime.Now.AddSeconds(seconds);
????????_CacheDictionary[key]?=?new?KeyValuePair<object,?DateTime?>(data,?expirationTime);
????}
????///?
????///?設置絕對過期緩存
????///?
????///?鍵<
????///?數據包
????public?void?Set(string?key,?object?data)
????{
????????this[key]?=?data;?//?下面代碼等效
????????//?_CacheDictionary[key]?=?new?KeyValuePair
????}
????///?
????///?通過key獲取緩存value
????///?2.被動過期
????///?
????///?
????///?
????///?
????public?T??Get(string?key)
????{
????????if?(Exist(key))
????????{
????????????//var?valueTime?=?_CacheDictionary[key];
????????????//return?(T)valueTime.Key;?//return?(T)this[key];
????????????bool?hasValue?=?_CacheDictionary.TryGetValue(key,?out?KeyValuePair<object,?DateTime?>?value);
????????????if?(hasValue)
????????????{
????????????????return?(T)value.Key;?//return?(T)this[key];
????????????}
????????}
????????return?default;
????}
????///?
????///?獲取所有的key
????///?
????///?
????public?ICollection<string>?GetKeys()?=>?_CacheDictionary.Keys;
????///?
????///?獲取緩存個數
????///?
????///?
????public?int?Count()
????{
????????int?count?=?0;
????????if?(_CacheDictionary?!=?null)
????????{
????????????count?=?_CacheDictionary.Count;
????????}
????????return?count;
????}
????///?
????///?刪除指定key的value
????///?
????///?
????public?void?Remove(string?key)
????{
????????if?(Exist(key))
????????{
????????????_CacheDictionary.TryRemove(key,?out?KeyValuePair<object,?DateTime?>?value);
????????}
????}
????///?
????///?清空所有緩存
????///?
????public?void?Cleaner()
????{
????????if?(_CacheDictionary?!=?null?&&?_CacheDictionary.Count?>?0)
????????{
????????????foreach?(var?key?in?_CacheDictionary.Keys)
????????????{
????????????????_CacheDictionary.TryRemove(key,?out?KeyValuePair<object,?DateTime?>?value);
????????????}
????????}
????}
????///?
????///?2.被動過期,保證任何過期緩存都無法取值
????///?檢查key是否存在
????///?
????///?
????///?
????public?bool?Exist(string?key)
????{
????????bool?isExist?=?false;
????????if?(!string.IsNullOrWhiteSpace(key)?&&?_CacheDictionary.ContainsKey(key))
????????{
????????????var?valTime?=?_CacheDictionary[key];
????????????if?(valTime.Value?!=?null?&&?valTime.Value?>?DateTime.Now)
????????????{
????????????????isExist?=?true;?//緩存沒過期
????????????}
????????????else
????????????{
????????????????if?(valTime.Value?==?null)
????????????????{
????????????????????isExist?=?true;?//永久緩存
????????????????}
????????????????else
????????????????{
????????????????????_CacheDictionary.TryRemove(key,?out?KeyValuePair<object,?DateTime?>?value);?//緩存過期清理
????????????????}
????????????}
????????}
????????return?isExist;
????}
}
Main方法使用緩存
由于項目是用控制臺程序編寫的,所以我們可以直接在Main方法中添加如下代碼:
var?customCache?=?CustomCacheHelper.GetSingleObj();
customCache.Set("key1",?"value1");
customCache.Set("key2",?"value2",?3);
customCache.Set("key3",?"value3",?6);
var?keys?=?customCache.GetKeys();
Console.WriteLine("首次打印:");
foreach?(var?key?in?keys)
{
????Console.WriteLine($"time:{DateTime.Now},key={key},value={customCache.Get<string>(key)}");
}
Console.WriteLine("睡眠5s后再次打?。?);
Thread.Sleep(5000);
foreach?(var?key?in?keys)
{
????Console.WriteLine($"time:{DateTime.Now},key={key},value={customCache.Get<string>(key)}");
}
這里的代碼中,我們添加了三組鍵值數據,其中一組不設置過期時間,另外兩組設置過期時間。 保存數據后,分別打印緩存中保存的數據,在第二次緩存打印之前,先讓線程休眠等待5秒(5000毫秒),并注意控制臺輸出的信息。
開始測試
從控制臺輸出的信息可以看到key=key2的值為空,這說明我們內部調用Exist方法已經生效,key2的值緩存的有效時間為3秒。 當第二次打印出信息時,此時已經休眠了5秒,key2中存儲的內存數據已經超時,而key3中存儲的值有效期為6秒,沒有超時,這樣就可以一一獲取對應的內存數據。
開始測試
通過上面的demo演示,我們實現了一個自定義的進程內緩存助手,可以很方便的導入到項目中使用。
portant;overflow-wrap: break-word !important;">portant;overflow-wrap: break-word !important;">portant;overflow-wrap: break-word !important;">portant;overflow-wrap: break-word !important;">推薦閱讀: portant;overflow-wrap: break-word !important;">inktype="text" imgurl="" imgdata="null" data-itemshowtype="11" tab="innerlink" data-linktype="2">微軟開源了一個 助力開發LLM 加持的應用的 工具包 semantic-kernel portant;overflow-wrap: break-word !important;">inktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">【譯】使用 ChatGPT 和 Azure Cosmos DB 構建智能應用程序 portant;overflow-wrap: break-word !important;">inktype="text" imgurl="" imgdata="null" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">實際體驗文心一言 VS ChatGPT portant;overflow-wrap: break-word !important;">inktype="text" imgurl="" imgdata="null" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">選擇 .NET 的 n 個理由 portant;overflow-wrap: break-word !important;">inktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">一個.NET開發的開源神級錄屏軟件 portant;overflow-wrap: break-word !important;">inktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">inktype="text" imgurl="" imgdata="null" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="outline: 0px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">跨平臺`ChatGpt` 客戶端 portant;overflow-wrap: break-word !important;">點擊下方卡片關注DotNet NB
portant;overflow-wrap: break-word !important;">一起交流學習
portant;overflow-wrap: break-word !important;">
portant;overflow-wrap: break-word !important;"> portant;overflow-wrap: break-word !important;">▲?點擊上方卡片關注DotNet NB,一起交流學習
portant;overflow-wrap: break-word !important;">請在公眾號后臺
portant;overflow-wrap: break-word !important;">回復?【路線圖】獲取.NET 2021開發者路線圖 portant;overflow-wrap: break-word !important;">回復?【原創內容】獲取公眾號原創內容 portant;overflow-wrap: break-word !important;">回復?【峰會視頻】獲取.NET Conf開發者大會視頻 portant;overflow-wrap: break-word !important;">回復?【個人簡介】獲取作者個人簡介 portant;overflow-wrap: break-word !important;">回復?【年終總結】獲取作者年終總結 portant;overflow-wrap: break-word !important;">回復?【加群】加入DotNet NB?交流學習群 portant;overflow-wrap: break-word !important;"> portant;overflow-wrap: break-word !important;">長按識別下方二維碼,或點擊閱讀原文。和我一起,交流學習,分享心得。 portant;overflow-wrap: break-word !important;"> portant;overflow-wrap: break-word !important;">
portant;overflow-wrap: break-word !important;">
portant;overflow-wrap: break-word !important;">