C# 内存缓存工具类 MemoryCacheUtil
C# 内存缓存工具类 MemoryCacheUtil

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Timers; namespace Utils
{
/// <summary>
/// 缓存
/// 缓存数据存储在内存中
/// 适用于CS项目,BS项目慎用
/// </summary>
public static class MemoryCacheUtil
{
#region 变量
/// <summary>
/// 内存缓存
/// </summary>
private static ConcurrentDictionary<string, CacheData> _cacheDict = new ConcurrentDictionary<string, CacheData>(); /// <summary>
/// 对不同的键提供不同的锁,用于读缓存
/// </summary>
private static ConcurrentDictionary<string, string> _dictLocksForReadCache = new ConcurrentDictionary<string, string>(); /// <summary>
/// 过期缓存检测Timer
/// </summary>
private static Timer _timerCheckCache;
#endregion #region 静态构造函数
static MemoryCacheUtil()
{
_timerCheckCache = new Timer();
_timerCheckCache.Interval = 60 * 1000;
_timerCheckCache.Elapsed += _timerCheckCache_Elapsed;
_timerCheckCache.Start();
}
#endregion #region 获取并缓存数据
/// <summary>
/// 获取并缓存数据
/// 高并发的情况建议使用此重载函数,防止重复写入内存缓存
/// </summary>
/// <param name="cacheKey">键</param>
/// <param name="func">在此方法中初始化数据</param>
/// <param name="expirationSeconds">缓存过期时间(秒),0表示永不过期</param>
/// <param name="refreshCache">立即刷新缓存</param>
public static T TryGetValue<T>(string cacheKey, Func<T> func, int expirationSeconds = 0, bool refreshCache = false)
{
lock (_dictLocksForReadCache.GetOrAdd(cacheKey, cacheKey))
{
object cacheValue = MemoryCacheUtil.GetValue(cacheKey);
if (cacheValue != null && !refreshCache)
{
return (T)cacheValue;
}
else
{
T value = func();
MemoryCacheUtil.SetValue(cacheKey, value, expirationSeconds);
return value;
}
}
}
#endregion #region SetValue 保存键值对
/// <summary>
/// 保存键值对
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="value">值</param>
/// <param name="expirationSeconds">过期时间(秒),0表示永不过期</param>
internal static void SetValue(string key, object value, int expirationSeconds = 0)
{
try
{
CacheData data = new CacheData(key, value);
data.updateTime = DateTime.Now;
data.expirationSeconds = expirationSeconds; CacheData temp;
_cacheDict.TryRemove(key, out temp);
_cacheDict.TryAdd(key, data);
}
catch (Exception ex)
{
LogUtil.Error(ex, "MemoryCacheUtil写缓存错误");
}
}
#endregion #region GetValue 获取键值对
/// <summary>
/// 获取键值对
/// </summary>
internal static object GetValue(string key)
{
try
{
CacheData data;
if (_cacheDict.TryGetValue(key, out data))
{
if (data.expirationSeconds > 0 && DateTime.Now.Subtract(data.updateTime).TotalSeconds > data.expirationSeconds)
{
CacheData temp;
_cacheDict.TryRemove(key, out temp);
return null;
}
return data.value;
}
return null;
}
catch (Exception ex)
{
LogUtil.Error(ex, "MemoryCacheUtil读缓存错误");
return null;
}
}
#endregion #region Delete 删除缓存
/// <summary>
/// 删除缓存
/// </summary>
internal static void Delete(string key)
{
CacheData temp;
_cacheDict.TryRemove(key, out temp);
}
#endregion #region DeleteAll 删除全部缓存
/// <summary>
/// 删除全部缓存
/// </summary>
internal static void DeleteAll()
{
_cacheDict.Clear();
}
#endregion #region 过期缓存检测
/// <summary>
/// 过期缓存检测
/// </summary>
private static void _timerCheckCache_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Task.Run(() =>
{
try
{
foreach (string cacheKey in _cacheDict.Keys.ToList())
{
CacheData data;
if (_cacheDict.TryGetValue(cacheKey, out data))
{
if (data.expirationSeconds > 0 && DateTime.Now.Subtract(data.updateTime).TotalSeconds > data.expirationSeconds)
{
CacheData temp;
string strTemp;
_cacheDict.TryRemove(cacheKey, out temp);
_dictLocksForReadCache.TryRemove(cacheKey, out strTemp);
}
}
}
}
catch (Exception ex)
{
LogUtil.Error(ex, "过期缓存检测出错");
}
});
}
#endregion }
}
为什么BS项目慎用?因为IIS会回收进程,所以需要注意一下。
为什么过期缓存检测遍历代码是foreach (string cacheKey in _cacheDict.Keys.ToList()),要使用ToList()?_cacheDict.Keys不是线程安全的,防止并发异常。
为什么加锁的代码是lock (_dictLocksForReadCache.GetOrAdd(cacheKey, cacheKey))?为了支持多线程并发,防止重复进入func函数。
CacheData类:

/// <summary>
/// 缓存数据
/// </summary>
[Serializable]
public class CacheData
{
/// <summary>
/// 键
/// </summary>
public string key { get; set; }
/// <summary>
/// 值
/// </summary>
public object value { get; set; }
/// <summary>
/// 缓存更新时间
/// </summary>
public DateTime updateTime { get; set; }
/// <summary>
/// 过期时间(秒),0表示永不过期
/// </summary>
public int expirationSeconds { get; set; } /// <summary>
/// 缓存数据
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="value">值</param>
public CacheData(string key, object value)
{
this.key = key;
this.value = value;
}
}
如何使用:

private void button2_Click(object sender, EventArgs e)
{
List<string> list = MemoryCacheUtil.TryGetValue<List<string>>("cacheKey001", () =>
{
return QueryData();
});
} /// <summary>
/// 模拟从数据库查询数据
/// </summary>
private List<string> QueryData()
{
List<string> result = new List<string>(); for (int i = 0; i < 10; i++)
{
result.Add(i.ToString());
} return result;
}
多线程并发测试:

private void TestMemoryCache()
{
Log("开始");
for (int i = 0; i < 5; i++)
{
Task.Run(() =>
{
string str1 = MemoryCacheUtil.TryGetValue<string>("1", () =>
{
Thread.Sleep(2000);
Log("取数据1");
return "1";
});
Log(str1);
}); Task.Run(() =>
{
string str2 = MemoryCacheUtil.TryGetValue<string>("2", () =>
{
Thread.Sleep(2000);
Log("取数据2");
return "2";
});
Log(str2);
}); Task.Run(() =>
{
string str3 = MemoryCacheUtil.TryGetValue<string>("3", () =>
{
Thread.Sleep(2000);
Log("取数据3");
return "3";
});
Log(str3);
});
}
}
C# 内存缓存工具类 MemoryCacheUtil的更多相关文章
- 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Caching; usi ...
- Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
Go/Python/Erlang编程语言对比分析及示例 本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...
- Cache【硬盘缓存工具类(包含内存缓存LruCache和磁盘缓存DiskLruCache)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 内存缓存LruCache和磁盘缓存DiskLruCache的封装类,主要用于图片缓存. 效果图 代码分析 内存缓存LruCache和 ...
- php 缓存工具类 实现网页缓存
php 缓存工具类 实现网页缓存 php程序在抵抗大流量访问的时候动态网站往往都是难以招架,所以要引入缓存机制,一般情况下有两种类型缓存 一.文件缓存 二.数据查询结果缓存,使用内存来实现高速缓存 本 ...
- thrift之TTransport层的内存缓存传输类TMemoryBuffer
内存缓存是简单的在内存进行读写操作的一种传输,任何时候想在上面写入数据都是放入缓存中,任何时候读操作数据也是来至于缓存.内存缓存的分配使用c语言的malloc类函数,分配的长度是需要长度的两倍,需要考 ...
- redis缓存工具类
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis ...
- redis缓存工具类,提供序列化接口
1.序列化工具类 package com.qicheshetuan.backend.util; import java.io.ByteArrayInputStream; import java.io. ...
- CookieUtils-浏览器缓存工具类
package cn.yonyong.myproject.commons.utils; import javax.servlet.http.Cookie; import javax.servlet.h ...
- 缓存工具类CacheHelper
代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...
- 基于spring的redisTemplate的缓存工具类
pom.xml文件添加 <!-- config redis data and client jar --><dependency> <groupId>org.spr ...
随机推荐
- Verilog语法基础
FPGA语法 逻辑值: 0:逻辑低电平,条件为假. 1:逻辑高电平,条件为真. z:高阻态,无驱动 x:未知逻辑电平,这既不是0也不是1,只是一个不稳定的状态. 关键字: module:表示模块的开始 ...
- UIPath初识和安装
即使没有人为你鼓掌,也要优雅的谢幕,感谢自己的认真付出. 一. UiPath组成 学习UiPath,我们一定先要了解Studio,Robot和Orchestrator这3个重要组成部分. UiPa ...
- C语言已知单链表LA=(a1,a2,…,am)和LB=(b1,b2,…,bn),编写程序按以下规则将它们合并成一个单链表LC,
LC=(a1,b1,-,am,bm,bm+1,-,bn),m<=n 或者 LC=(a1,b1,-,bn,an,an+1,-,am),m>n /* 开发者:慢蜗牛 开发时间:2020.6.1 ...
- 龙芯发布 .NET 8 SDK 8.0.100-ea1(试用版)
随着.NET 8的发布,国内的社区朋友们也很关心龙芯.NET 团队对于Loongarch .NET 8的发布时间,目前从龙芯.NET编译器团队已经在龙芯.NET 官网上发布龙芯.NET 8 SDK-8 ...
- 三菱PLC 轻松数采
目前市面上数采的软件有很多,但是用的最为省力最为简单的就是kepserver了,在kepserver的应用中,有对应的三菱驱动针对于三菱PLC,三菱驱动支持多个Mitsubishi 协议,包括 MEL ...
- Netty源码学习8——从ThreadLocal到FastThreadLocal(如何让FastThreadLocal内存泄漏doge)
系列文章目录和关于我 一丶引入 在前面的netty源码学习中经常看到FastThreadLocal的身影,这一篇我们将从ThreadLocal说起,来学习FastThreadLocal的设计(< ...
- [ABC280F] Pay or Receive
Problem Statement There are $N$ towns numbered $1,\ldots,N$ and $M$ roads numbered $1,\ldots,M$. Roa ...
- 开源地图库OpenLayers的简单使用
引言 最近在学习可视化的东西,这让我想起了一些以前用过的图表库,其实我在日常做的大多是普通的需求,可视化方面应用的并不多,只是偶尔会因为个别特殊的需求,去借助一些图表库来实现图表的展示,这些普通的图表 ...
- Python 潮流周刊第 31 期(摘要)
本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...
- 数字孪生与GIS结合,为智慧交通带来的改变
在当代社会,交通问题已经成为城市发展中的一个重要挑战.交通拥堵.安全隐患.环境污染等问题给人们的出行带来了许多不便和困扰.然而,随着数字孪生技术与地理信息系统(GIS)的融合,我们迎来了智慧交通的新时 ...