C# 实现 key-value 结构自定义缓存 CustomCache
创始人
2024-06-01 11:12:28
0

功能需求

使用 C# 编写一个 key-value 结构进程内缓存,实现数据的缓存操作,此处所用到的知识点如下:

  • 线程安全的字典 ConcurrentDictionary
  • 设计模式之单例模式(Singleton);
  • 缓存数据【主动 & 被动】过期模式;

cache

key-value 缓存实现

说明:此处基于 .net 6 平台创建控制台项目。

  • 新建 ConsoleApp 项目,添加 CustomCacheHelper.cs 类;
  1. 导入命名空间(namespace
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
  1. CustomCacheHelper.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> _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 listKey = _CacheDictionary.Keys;foreach (var key in listKey){var valueTime = _CacheDictionary[key];if (valueTime.Value < DateTime.Now){_CacheDictionary.TryRemove(key, out KeyValuePair value);}}}}});}/// /// 索引器/// /// /// public object this[string key]{get => _CacheDictionary[key];set => _CacheDictionary[key] = new KeyValuePair(value, null);}/// /// 设置相对过期缓存/// /// 键/// 数据包/// 相对过期时间public void Set(string key, object data, int seconds){var expirationTime = DateTime.Now.AddSeconds(seconds);_CacheDictionary[key] = new KeyValuePair(data, expirationTime);}/// /// 设置绝对过期缓存/// /// 键</// 数据包public void Set(string key, object data){this[key] = data; // 下面代码等效// _CacheDictionary[key] = new KeyValuePair(data, null);}/// /// 通过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 value);if (hasValue){return (T)value.Key; //return (T)this[key];}}return default;}/// /// 获取所有的key/// /// public ICollection 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 value);}}/// /// 清空所有缓存/// public void Cleaner(){if (_CacheDictionary != null && _CacheDictionary.Count > 0){foreach (var key in _CacheDictionary.Keys){_CacheDictionary.TryRemove(key, out KeyValuePair 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 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(key)}");
}Console.WriteLine("睡眠5s后再次打印:");
Thread.Sleep(5000);
foreach (var key in keys)
{Console.WriteLine($"time:{DateTime.Now},key={key},value={customCache.Get(key)}");
}

此处代码中我们添加了三组 key-vaule 数据,其中一个是没有设置过期时间,另外两个设置过期时间,保存数据后,分别打印缓存中保存的数据,再第二次缓存打印前,先让线程睡眠等待 5 秒(5000毫秒),注意观察控制台输出的信息。

ConsoleApp 启动测试

从控制台输出的信息中,我们可以看到 key=key2value 值为空,说明我们内部调用 Exist 方法生效了,key2value 缓存有效时间是 3 秒,第二次打印输出信息时,此时已经睡眠 5 秒,相对于 key2 存储的内存数据已经超时,而 key3value 存储的有效时间是 6 秒,没有超时,所以能个获取到对应的内存数据。

启动测试

通过上面的 demo 演示,我们就实现了一个自定义的进程内缓存助手,在项目中可以很方便的导入使用。

相关内容

热门资讯

文华已任新疆维吾尔自治区发改委... 近日,新疆维吾尔自治区发展和改革委员会官网更新后显示,文华已任自治区发改委党组书记、副主任,自治区对...
薪水合心是什么意思? 薪水合心是什么意思?就是祝你的工资能让能让你放心。比较适合你,称心如意发的工资很适合心意,能满足自己...
在津银行机构通过投贷联动模式累... 转自:新华财经新华财经天津7月9日电(记者李亭)记者9日从天津市银行业重点合作投资机构参考清单202...
国网甘肃电科院开展国内首(台)...   7月6日,国网甘肃电科院技术人员完成国内首(台)套C4环保型330千伏断路器设备制造阶段关键点出...
警察冲上门强制拔卡断网!差两秒... 01:23封面新闻记者 于婷“再晚一步这笔钱可能就进了骗子的账户!”近日,成都武侯区的王婆婆(化名)...
“毛孩子”催生3000亿“家人... 转自:邯郸网络广播电视台随着人们生活水平的提高和消费观念的转变,宠物已从“动物伙伴”变为情感寄托和家...
荣耀“阿尔法之旅”联结九国青年...   炒股就看金麒麟分析师研报,权威,专业,及时,全面,助您挖掘潜力主题机会! 7月8日,一场旨在促...
关于宫崎骏的书,哪本好,大家推... 关于宫崎骏的书,哪本好,大家推荐一下评论一下吧,谢谢楼主你好,我曾经买过一本书叫《宫崎骏的迷路森林》...
纳入失信名单前给予企业宽限期,...   长沙晚报掌上长沙7月9日讯(全媒体记者 黄能)7月9日,湖南省高级人民法院联合省发展改革委、省工...
迪丽热巴利剑玫瑰首部打拐刑侦剧 【#迪丽热巴利剑玫瑰首部打拐刑侦剧#】7月9日,@Dear-迪丽热巴 @金世佳 主演的电视剧《利剑...