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的更多相关文章

  1. 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!

    using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Caching; usi ...

  2. Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!

    Go/Python/Erlang编程语言对比分析及示例   本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...

  3. Cache【硬盘缓存工具类(包含内存缓存LruCache和磁盘缓存DiskLruCache)】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 内存缓存LruCache和磁盘缓存DiskLruCache的封装类,主要用于图片缓存. 效果图 代码分析 内存缓存LruCache和 ...

  4. php 缓存工具类 实现网页缓存

    php 缓存工具类 实现网页缓存 php程序在抵抗大流量访问的时候动态网站往往都是难以招架,所以要引入缓存机制,一般情况下有两种类型缓存 一.文件缓存 二.数据查询结果缓存,使用内存来实现高速缓存 本 ...

  5. thrift之TTransport层的内存缓存传输类TMemoryBuffer

    内存缓存是简单的在内存进行读写操作的一种传输,任何时候想在上面写入数据都是放入缓存中,任何时候读操作数据也是来至于缓存.内存缓存的分配使用c语言的malloc类函数,分配的长度是需要长度的两倍,需要考 ...

  6. redis缓存工具类

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis ...

  7. redis缓存工具类,提供序列化接口

    1.序列化工具类 package com.qicheshetuan.backend.util; import java.io.ByteArrayInputStream; import java.io. ...

  8. CookieUtils-浏览器缓存工具类

    package cn.yonyong.myproject.commons.utils; import javax.servlet.http.Cookie; import javax.servlet.h ...

  9. 缓存工具类CacheHelper

    代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  10. 基于spring的redisTemplate的缓存工具类

    pom.xml文件添加 <!-- config redis data and client jar --><dependency> <groupId>org.spr ...

随机推荐

  1. Vue3 第三章

    Vite目录 public 下面的不会被编译 可以存放静态资源 assets 下面可以存放可编译的静态资源 components 下面用来存放我们的组件 App.vue 是全局组件 main ts 全 ...

  2. 【Javaweb】implements Serializable是什么意思?反序列化是什么意思?

    为了保证数据传输的可靠 性,常常要implements Serializable,为什么? 对象本质上是虚无缥缈的,只是内存中的一个地址,如果想要让对象持久化,让对象在网络上传输,总不可能传送一个内存 ...

  3. 【Android】无法通过drawable下的selector类型改变背景颜色?

    举例 我在darwable目录下创建了selector文件,并设置了如下内容 <?xml version="1.0" encoding="utf-8"?& ...

  4. PX4安装环境测试

    1.ROS环境测试 安装ROS版本:melodic roscore // 注意下面是打开一个新的终端,roscore一直在运行 rosrun turtlesim turtlesim_node // 再 ...

  5. Codeforces Round 903 (Div. 3)

    Codeforces Round 903 (Div. 3) A. Don't Try to Count 大概题意给你两个字符串a,b.a串可进行的操作为将整个a串复制到之前的a串后面(直接用a+a即可 ...

  6. 有哪些可部署的, 无需编程的,基于WEB的数据可视化工具

    基于Web的数据可视化工具在当今数字化时代具有重要的作用,可以帮助企业和个人更好地理解和利用数据.以下是一些无需编程即可部署的基于Web的数据可视化工具,详细描述如下:Tableau Public: ...

  7. 什么是RPC协议

    工作的时候,第一次接触CRPC协议,当时就很懵,啥是CRPC协议,一脸懵逼,于是就到网上去搜,填充知识空缺. 不少解释显得非常官方,我相信大家在各种平台上也都看到过,解释了又好像没解释,都在用一个我们 ...

  8. Cocos2d-js 游戏切后台和返回游戏,系统监听事件

    在日常游戏开发中,我们会发现,实时类操作的游戏,在模拟器中切后台,然后切回游戏,会出现很多异常. 很幸运,Cocos官方已经为我们预留了接口 1 LogicGame.addSystemListener ...

  9. Json Schema简介和Json Schema的.net实现库 LateApexEarlySpeed.Json.Schema

    什么是Json Schema ? Json Schema是一种声明式语言,它可以用来标识Json的结构,数据类型和数据的具体限制,它提供了描述期望Json结构的标准化方法. 利用Json Schema ...

  10. Using PostMessage/SendMessage to send keys to c# IE WebBrowser

    [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool PostM ...