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 ...
随机推荐
- 矩阵重叠 (3.18 leetcode每日打卡)
度简单66收藏分享切换为英文关注反馈矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标. 如果相交的面积为正,则称两矩形 ...
- 关于一类最优解存在长度为 $k$ 的循环节的问题
灵感来源 问题形式:给定长度为 \(n\) 的序列,要求选出一些位置,使这些位置满足限制条件 \(T\),其中 \(T\) 可以表述为一个长度为 \(k\) 的环满足条件 \(T'\),选出第 \(i ...
- MySQL大表设计怎么做?
MySQL是一种常用的关系型数据库管理系统,它在处理大表时需要特别注意设计和优化.下面将详细介绍MySQL大表的设计原则和优化策略. 1. 数据库设计 数据库范式化:将数据按照规范的关系模型进行拆分和 ...
- 【漏洞分析】Reflection Token 反射型代币攻击事件通用分析思路
在本篇文章中,我将通过一个攻击事件引出 Reflection Token 攻击事件的一个通用分析思路. 关于 Reflection Token 的其他案例分析,可以参考BEVO代币攻击事件分析及复现一 ...
- 浅谈SQL优化小技巧
回顾MySQL的执行过程,帮助介绍如何进行sql优化. (1)客户端发送一条查询语句到服务器: (2)服务器先查询缓存,如果命中缓存,则立即返回存储在缓存中的数据: (3)未命中缓存后,MySQL通过 ...
- Markdown References
每次写文章,用到都要查一下的Markdown语法 字体颜色 [Markdown笔记]设置字体颜色 字体颜色 Font colors Decrsiption Demonstration Effect 选 ...
- 第一行代码 Android 第三版读后感
<第一行代码Android 第三版>是一本非常好的Android开发入门书籍.本书结合作者的丰富经验和实际案例,通过一步一步的介绍,详细地讲解了Android开发的各个方面,包括Andro ...
- [python]数据分析--数据清洗处理case1
数据预处理案例1 主要涉及pandas读取csv文件,缺失值和重复值处理,分组计数,字段类型转换 ,结果写入到Excel. 根据要求对CSV数据集进行处理要求如下: 保留数据关键信息:time.lat ...
- 微调baichuan2-7b遇到的显存坑
问题描述: 微调baichuan2-7b模型,验证一轮后继续训练第一个iteration显存大幅增加 项目链接: https://github.com/wp931120/baichuan_sft_lo ...
- 使用容器快速在阿里云 ECS 多节点上搭建 Citus 12.1 集群
阿里云 ECS 机器节点 这里我们使用两台同一区域的 ECS 机器. 机器配置:2 核 2 G.(ps: 阿里云 99 元一年的活动) 一台安装 coordinator(协调器),这里内网 IP 为 ...