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

相关内容

热门资讯

求经典台词和经典旁白 求经典台词和经典旁白谁有霹雳布袋戏里的经典对白和经典旁白啊?朋友,你尝过失去的滋味吗? 很多人在即将...
小王子第二章主要内容概括 小王子第二章主要内容概括小王子第二章主要内容概括小王子第二章主要内容概括
爱情睡醒了第15集里刘小贝和项... 爱情睡醒了第15集里刘小贝和项天骐跳舞时唱的那首歌是什么谢谢开始找舞伴的时候是林俊杰的《背对背拥抱》...
世界是什么?世界是什么概念?可... 世界是什么?世界是什么概念?可以干什么?物质的和意识的 除了我们生活的地方 比方说山 河 公路 ...
全职猎人中小杰和奇牙拿一集被抓 全职猎人中小杰和奇牙拿一集被抓动画片是第五十九集,五十八集被发现,五十九被带回基地,六十逃走
“不周山”意思是什么 “不周山”意思是什么快快快快......一座山,神话里被共工撞倒了。
《揭秘》一元一分15张跑得快群... 一元一分麻将群加群主微【ab120590】【tj525555】 【mj120590】等风也等你。喜欢...
玩家必看手机正规红中麻将群@2... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
始作俑者15张跑的快群@24小... 微信一元麻将群群主微【ab120590】 【tj525555】【mj120590】一元一分群内结算,...
《重大通知》24小时一元红中麻... 加V【ab120590】【tj525555】【mj120590】红中癞子、跑得快,等等,加不上微信就...
盘点一下正规一块红中麻将群@2... 一元一分麻将群加群主微:微【ab120590】 【mj120590】【tj525555】喜欢手机上打...
(免押金)上下分一元一分麻将群... 微【ab120590】 【mj120590】【tj525555】专业麻将群三年房费全网最低,APP苹...
[解读]正规红中麻将跑的快@群... 微信一元麻将群群主微【ab120590】 【tj525555】【mj120590】一元一分群内结算,...
《普及一下》全天24小时红中... 微【ab120590】 【mj120590】【tj525555】专业麻将群三年房费全网最低,APP苹...
优酷视频一元一分正规红中麻将... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
《火爆》加入附近红中麻将群@(... 群主微【ab120590】 【mj120590】【tj525555】免带押进群,群内跑包包赔支持验证...
《字节跳动》哪里有一元一分红中... 1.进群方式-[ab120590]或者《mj120590》【tj525555】--QQ(QQ4434...
全网普及红中癞子麻将群@202... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
「独家解读」一元一分麻将群哪里... 1.进群方式《ab120590》或者《mj120590》《tj525555》--QQ(4434063...
通知24小时不熄火跑的快群@2... 1.进群方式《ab120590》或者《mj120590》《tj525555》--QQ(4434063...