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 演示,我们就实现了一个自定义的进程内缓存助手,在项目中可以很方便的导入使用。

相关内容

热门资讯

虞书欣谈成名的代价令人心疼,如... 虞书欣谈成名的代价令人心疼,如今她在圈内的前景如何?虞书欣在圈内前景是很不错的,大家都很喜欢她,也有...
最有效的减肥食谱 最有效的减肥食谱谁有最有效的减肥食谱呢?麻烦给一个吧?急求最有效的减肥食谱,听说有一个什么汤的可以很...
关晓彤鹿晗被曝月底会分手,你对... 关晓彤鹿晗被曝月底会分手,你对于他们两个的爱情有什么看法?当初我也觉得他们俩的感情肯定不会长久的,但...
她曾在家中喂猪,却被张艺谋相中... 她曾在家中喂猪,却被张艺谋相中一夜成名,魏敏芝如今过得怎样?魏敏芝过得非常不错啊,而且当地的头衔也是...
电影《中邪》主要讲了什么? 电影《中邪》主要讲了什么?中邪的剧情简介 · · · · · ·大学生丁鑫和刘梦为拍摄农村风俗纪录片...
可以在营业厅查到短信的内容吗? 可以在营业厅查到短信的内容吗?查自己的短信==如果你是本人应该可以…不是本人是不可以的那是别人的隐私...
春日时雨时晴,杏花开时,小雨落... 春日时雨时晴,杏花开时,小雨落在身上,衣服欲湿未湿;杨柳风最柔,吹到脸上也下觉其寒。是什么诗句沾衣欲...
低学历的女人真的不能娶吗? 低学历的女人真的不能娶吗?我觉得不是的,娶妻子还是主要看对方的品性如何,而不是在意对方的学历。不一定...
电影配音问题 懂的进来 不是很... 电影配音问题 懂的进来 不是很难我想知道一个问题 比如说 一个电影 演员是 X 那他的说...可以是...
关于大蒜的谜语有哪些 关于大蒜的谜语有哪些有关蒜的谜语有:两二小,头长草 (打字一)谜底:蒜弟兄七八个,围着柱子坐,只要一...
怎么夸老师漂亮 怎么夸老师漂亮老师您长得太有气质了,非常出众,我身为一个女孩子都快要把持不住了。就直接一点说:老师你...
一般怎么钢琴即兴伴奏,一拿到简... 一般怎么钢琴即兴伴奏,一拿到简谱就能伴奏的和弦 天空之城简易般的可一参考 摸摸就出来的 弹一个音 ...
我对异地女友说,异地太苦了我真... 我对异地女友说,异地太苦了我真心问你,你和我一起内心快乐吗?她说,不管日子再苦,有你就是甜的?你一个...
为什么叫镇江 为什么叫镇江为什么叫镇江意义为"Garrison of the Yangtze River"
在足球历史上,阿贾克斯都获得过... 在足球历史上,阿贾克斯都获得过多少次欧冠?一共应该是获得过4次冠军,而且他真的是特别厉害,很少有人可...
时间简史是谁写的? 时间简史是谁写的?史蒂芬·威廉·霍金
我爱她,但她爱他。 我爱她,但她爱他。如果换了我是你!我会一直的爱着她!她爱着他,你又爱着他!她知道爱一个不爱自己人的资...
歌词:我是你的月亮,是你夜里的... 歌词:我是你的月亮,是你夜里的光芒。叫月光曲,嘿嘿
枪神纪里面的英文歌曲叫什么? 枪神纪里面的英文歌曲叫什么?枪神纪里面的英文歌曲叫什么?一首是男的一首是女的,女的那首好像有一句是,...
中外小朋友 大家手拉手 来自五... 中外小朋友 大家手拉手 来自五大洲 是什么歌名?中外小朋友 大家手拉手 来自五大洲 是什么歌名?《庆...