内存缓存MemoryCache

内存缓存MemoryCache实现了ICache接口,Redis同样实现了ICache接口,两者在缓存操作上达到了高度抽象统一。应用设计时一律使用ICache接口,开发环境装配为MemoryCache,生产环境根据分布式需要可以装配为Redis。如果应用系统没有分布式需求,继续使用MemoryCache更好。

超高性能

MemoryCache核心是并行字典ConcurrentDictionary,由于省去了序列化和网络通信,使得它具有千万级超高性能(普通台式机实测2.87亿tps)。

MemoryCache支持过期时间,默认容量10万个,未过期key超过该值后,每60秒根据LRU清理溢出部分。

常用于进程内千万级以下数据缓存场景。

本机测试数据如下(I9-10900K):

Test v1.0.0.1130 Build 2021-01-31 19:33:32 .NETCoreApp,Version=v5.0
Test 
Memory性能测试[顺序],批大小[0],逻辑处理器 20 个
测试 10,000,000 项,  1 线程
赋值 耗时     934ms 速度 10,706,638 ops
读取 耗时     989ms 速度 10,111,223 ops
删除 耗时     310ms 速度 32,258,064 ops
累加 耗时     584ms 速度 17,123,287 ops
测试 20,000,000 项,  2 线程
赋值 耗时     927ms 速度 21,574,973 ops
读取 耗时   1,024ms 速度 19,531,250 ops
删除 耗时     319ms 速度 62,695,924 ops
累加 耗时     594ms 速度 33,670,033 ops
测试 40,000,000 项,  4 线程
赋值 耗时   1,011ms 速度 39,564,787 ops
读取 耗时   1,039ms 速度 38,498,556 ops
删除 耗时   1,636ms 速度 24,449,877 ops
累加 耗时     608ms 速度 65,789,473 ops
测试 80,000,000 项,  8 线程
赋值 耗时     989ms 速度 80,889,787 ops
读取 耗时   1,227ms 速度 65,199,674 ops
删除 耗时   1,858ms 速度 43,057,050 ops
累加 耗时     675ms 速度 118,518,518 ops
测试 200,000,000 项, 20 线程
赋值 耗时   1,644ms 速度 121,654,501 ops
读取 耗时   1,807ms 速度 110,680,686 ops
删除 耗时   2,936ms 速度 68,119,891 ops
累加 耗时   1,569ms 速度 127,469,725 ops
测试 200,000,000 项, 64 线程
赋值 耗时   1,686ms 速度 118,623,962 ops
读取 耗时   1,877ms 速度 106,553,010 ops
删除 耗时     695ms 速度 287,769,784 ops
累加 耗时   1,585ms 速度 126,182,965 ops
总测试数据:2,200,000,042

ICache接口

ICache是缓存抽象接口,主要实现是MemoryCache和Redis

/// <summary>缓存接口</summary>
public interface ICache
{#region 属性/// <summary>名称</summary>String Name { get; }/// <summary>默认缓存时间。默认0秒表示不过期</summary>Int32 Expire { get; set; }/// <summary>获取和设置缓存,永不过期</summary>/// <param name="key"></param>/// <returns></returns>Object this[String key] { get; set; }/// <summary>缓存个数</summary>Int32 Count { get; }/// <summary>所有键</summary>ICollection<String> Keys { get; }#endregion#region 基础操作/// <summary>是否包含缓存项</summary>/// <param name="key"></param>/// <returns></returns>Boolean ContainsKey(String key);/// <summary>设置缓存项</summary>/// <param name="key">键</param>/// <param name="value">值</param>/// <param name="expire">过期时间,秒。小于0时采用默认缓存时间<seealso cref="Expire"/></param>/// <returns></returns>Boolean Set<T>(String key, T value, Int32 expire = -1);/// <summary>设置缓存项</summary>/// <param name="key">键</param>/// <param name="value">值</param>/// <param name="expire">过期时间</param>/// <returns></returns>Boolean Set<T>(String key, T value, TimeSpan expire);/// <summary>获取缓存项</summary>/// <param name="key">键</param>/// <returns></returns>T Get<T>(String key);/// <summary>批量移除缓存项</summary>/// <param name="keys">键集合</param>/// <returns></returns>Int32 Remove(params String[] keys);/// <summary>清空所有缓存项</summary>void Clear();/// <summary>设置缓存项有效期</summary>/// <param name="key">键</param>/// <param name="expire">过期时间</param>Boolean SetExpire(String key, TimeSpan expire);/// <summary>获取缓存项有效期</summary>/// <param name="key">键</param>/// <returns></returns>TimeSpan GetExpire(String key);#endregion#region 集合操作/// <summary>批量获取缓存项</summary>/// <typeparam name="T"></typeparam>/// <param name="keys"></param>/// <returns></returns>IDictionary<String, T> GetAll<T>(IEnumerable<String> keys);/// <summary>批量设置缓存项</summary>/// <typeparam name="T"></typeparam>/// <param name="values"></param>/// <param name="expire">过期时间,秒。小于0时采用默认缓存时间<seealso cref="Expire"/></param>void SetAll<T>(IDictionary<String, T> values, Int32 expire = -1);/// <summary>获取列表</summary>/// <typeparam name="T">元素类型</typeparam>/// <param name="key">键</param>/// <returns></returns>IList<T> GetList<T>(String key);/// <summary>获取哈希</summary>/// <typeparam name="T">元素类型</typeparam>/// <param name="key">键</param>/// <returns></returns>IDictionary<String, T> GetDictionary<T>(String key);/// <summary>获取队列</summary>/// <typeparam name="T">元素类型</typeparam>/// <param name="key">键</param>/// <returns></returns>IProducerConsumer<T> GetQueue<T>(String key);/// <summary>获取栈</summary>/// <typeparam name="T">元素类型</typeparam>/// <param name="key">键</param>/// <returns></returns>IProducerConsumer<T> GetStack<T>(String key);/// <summary>获取Set</summary>/// <typeparam name="T"></typeparam>/// <param name="key"></param>/// <returns></returns>ICollection<T> GetSet<T>(String key);#endregion#region 高级操作/// <summary>添加,已存在时不更新</summary>/// <typeparam name="T">值类型</typeparam>/// <param name="key">键</param>/// <param name="value">值</param>/// <param name="expire">过期时间,秒。小于0时采用默认缓存时间<seealso cref="Cache.Expire"/></param>/// <returns></returns>Boolean Add<T>(String key, T value, Int32 expire = -1);/// <summary>设置新值并获取旧值,原子操作</summary>/// <remarks>/// 常常配合Increment使用,用于累加到一定数后重置归零,又避免多线程冲突。/// </remarks>/// <typeparam name="T">值类型</typeparam>/// <param name="key">键</param>/// <param name="value">值</param>/// <returns></returns>T Replace<T>(String key, T value);/// <summary>尝试获取指定键,返回是否包含值。有可能缓存项刚好是默认值,或者只是反序列化失败,解决缓存穿透问题</summary>/// <typeparam name="T">值类型</typeparam>/// <param name="key">键</param>/// <param name="value">值。即使有值也不一定能够返回,可能缓存项刚好是默认值,或者只是反序列化失败</param>/// <returns>返回是否包含值,即使反序列化失败</returns>Boolean TryGetValue<T>(String key, out T value);/// <summary>累加,原子操作</summary>/// <param name="key">键</param>/// <param name="value">变化量</param>/// <returns></returns>Int64 Increment(String key, Int64 value);/// <summary>累加,原子操作</summary>/// <param name="key">键</param>/// <param name="value">变化量</param>/// <returns></returns>Double Increment(String key, Double value);/// <summary>递减,原子操作</summary>/// <param name="key">键</param>/// <param name="value">变化量</param>/// <returns></returns>Int64 Decrement(String key, Int64 value);/// <summary>递减,原子操作</summary>/// <param name="key">键</param>/// <param name="value">变化量</param>/// <returns></returns>Double Decrement(String key, Double value);#endregion#region 事务/// <summary>提交变更。部分提供者需要刷盘</summary>/// <returns></returns>Int32 Commit();/// <summary>申请分布式锁</summary>/// <param name="key">要锁定的key</param>/// <param name="msTimeout"></param>/// <returns></returns>IDisposable AcquireLock(String key, Int32 msTimeout);#endregion#region 性能测试/// <summary>多线程性能测试</summary>/// <param name="rand">随机读写。顺序,每个线程多次操作一个key;随机,每个线程每次操作不同key</param>/// <param name="batch">批量操作。默认0不分批,分批仅针对随机读写,对顺序读写的单key操作没有意义</param>Int64 Bench(Boolean rand = false, Int32 batch = 0);#endregion
}

基本用法

添删改查基本功能,Get/Set/Count/ContainsKey/Remove

var ic = new MemoryCache();
var key = "Name";
var key2 = "Company";
ic.Set(key, "大石头");
ic.Set(key2, "新生命");
Assert.Equal("大石头", ic.Get<String>(key));
Assert.Equal("新生命", ic.Get<String>(key2));
var count = ic.Count;
Assert.True(count >= 2);
// Keys
var keys = ic.Keys;
Assert.True(keys.Contains(key));
// 过期时间
ic.SetExpire(key, TimeSpan.FromSeconds(1));
var ts = ic.GetExpire(key);
Assert.True(ts.TotalSeconds > 0 && ts.TotalSeconds < 2, "过期时间");
var rs = ic.Remove(key2);
Assert.Equal(1, rs);
Assert.False(ic.ContainsKey(key2));
ic.Clear();
Assert.True(ic.Count == 0);

其中Set的第三个参数支持过期时间,单位秒。

集合操作

SetAll/GetAll 是高吞吐的关键,其中SetAll第二参数支持过期时间,单位秒

var ic = new MemoryCache();
var dic = new Dictionary<String, String>
{["111"] = "123",["222"] = "abc",["大石头"] = "学无先后达者为师"
};
ic.SetAll(dic);
var dic2 = ic.GetAll<String>(dic.Keys);
Assert.Equal(dic.Count, dic2.Count);
foreach (var item in dic)
{Assert.Equal(item.Value, dic2[item.Key]);
}

高级操作

MemoryCache有几个非常好用的高级操作,全部都是线程安全:

  • Add。添加,已存在时不更新,常用于锁争夺。例如,可用于判断指定订单是否处理过,加上过期时间,就是我们经常说的多少小时去重。

  • Replace。设置新值并获取旧值,原子操作

  • TryGetValue。尝试获取指定键,返回是否包含值。有可能缓存项刚好是默认值

  • Increment。累加

  • Decrement。累减

缓存过期策略

MemoryCache内置LRU淘汰算法,当缓存项超过最大值Capacity(默认10万)时,剔除最久未使用的缓存项,以避免内存占用过大。

缓存项未达到最大值Capacity时,MemoryCache定时检查并剔除过期项。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305226.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

quicktype游戏java程序_使用QuickType工具从json自动生成类型声明代码

一、QuickType 工具功能简介QuickType 是一款可以根据 json 文本生成指定语言(如 Type Script&#xff0c;C&#xff0c;,Java&#xff0c;C#&#xff0c;Go 等)类型声明代码的工具。例如我们在写接口调用处理收到响应数据的逻辑时一般分为如下两步&#xff1a; 1.根据接口返回…

endpointimpl怎么填参数_这是一篇VLOOKUP函数家族主要用法的合集,XLOOKUP来了!真香!但是,没有office365吃不着怎么办?...

最近这几个月&#xff0c;XLOOKUP震惊了Excel界&#xff0c;传言三头六臂无所不能&#xff0c;一个人把LOOKUP全家兄弟姐妹的活都给抢了。最开始我是不以为意的&#xff0c;但是相关的信息越来越多&#xff0c;我终于忍不住&#xff0c;今天去买了一套office365&#xff0c;发现…

1个月教你学会用Python实现机器学习

什么是机器学习&#xff1f;在最简单的层面上&#xff0c;机器学习只是优化数学方程式的过程。有几种不同的机器学习&#xff0c;都有不同的目的。机器学习中最流行的两种形式是监督学习和无监督的学习。 我们将在下面介绍他们的工作原理&#xff1a;. 监督学习&#xff1a;监督…

ASP.NET Core 5 在IIS,Nginx,Caddy下的性能测试

点击上方蓝字关注“汪宇杰博客”导语ASP.NET Core 从 2.2 版本起&#xff0c;在 IIS 下可以使用 InProcess 模式提高性能&#xff0c;国外大神 Rick Strahl 对此有一片详细的文章。3年过去了&#xff0c;现在 ASP.NET Core 已经到了 5.0 版本&#xff0c;不同服务器之间的性能有…

sql两个表查不同数据_产品操作MySQL第6篇 – 数据过滤-WHERE子句

MYSQL本资料为产品岗位作为日常工作参考&#xff0c;语言口语化At 2019/4/26 By David.Yang如何使用限定条件来进行数据过滤&#xff1f;在前问当中&#xff0c;我们已经学会到了SELECT查询&#xff0c;在过程当中多次接触了WHERE这个关键词&#xff0c;打过预防针应该知道他就…

win10必须禁用的服务_【亲测】Win10系统如何彻底禁止自动更新 亲测有效的Win10关闭自动更新方法...

昨天有人称Win10系统更新依然无法彻底关闭&#xff0c;今天再来补充一下&#xff0c;肯定可以&#xff01;不少用户反映自己的Win10系统更新无法彻底关闭&#xff0c;网上提供的关闭Win10更新的教程&#xff0c;关闭之后还是会自动更新Win10系统&#xff0c;而今天装机之家分享…

国庆中秋活动——超强AR/3D地球仪!带你领略世界风光!我们未必能环游世界,但都该有个地球仪

通知&#xff01;通知&#xff01;通知&#xff01;&#xff01;&#xff01; 玩酷屋十一黄金优惠限时限量秒杀活动&#xff0c;能抢到算你厉害&#xff1a; 1、活动期间 2017/10/03 22:30 ——2017/10/06 22:30 2、【北斗AR地球仪】原价 299元&#xff0c;秒杀活动价 269元…

flask mysql项目模板渲染_21. Flask 模板 - 宏、继承、包含

宏的概念类似于python中的函数&#xff0c;宏的作用就是在模板中重复利用代码&#xff0c;避免代码冗余。Jinja2支持宏&#xff0c;还可以导入宏&#xff0c;需要在多处重复使用的模板代码片段可以写入单独的文件&#xff0c;再包含在所有模板中&#xff0c;以避免重复。简单定…

如何在 ASP.Net Core 中使用 MiniProfiler

web应用程序的性能相信是大家普遍关心的一个问题&#xff0c;也相信大家有很多工具可用来分析应用程序的性能并能够找到其中的瓶颈&#xff0c;MiniProfiler 就是这个领域中的一款产品&#xff0c;它是一款简单的&#xff0c;功能强大的web应用分析工具&#xff0c;MiniProfile…

java 计时_Breitling(百年灵)世界时间终极计时腕表

所有热爱旅行的冒险家可以尽情期待&#xff0c;一款适合所有手腕的全新尺寸“旅行计时腕表”将在今年巴塞尔表展上华彩亮相。百年灵世界时间终极计时腕表(Chronomat 44 GMT)&#xff0c;适合腕间的完美尺寸&#xff0c;便捷的三时区时间显示&#xff0c;超凡的百年灵自产机芯&a…

python时钟罗盘酷炫代码_抖音上的时钟屏保,被我改造完用来表白

作者&#xff1a;爱编程的小和尚原文链接&#xff1a;https://blog.csdn.net/Newbie___/article/details/105378852抖音上很火的时钟屏保&#xff0c;被我改造完后用来准备准备准备表白&#xff0c;谁说程序员不浪漫&#xff1f;&#xff01;不知道一直关注小编我的小伙伴们之前…

大数据|意不意外?今年卖得最好的月饼是这个馅的……

中秋节&#xff0c;你家的月饼都吃完了吗&#xff1f; 淘宝、天猫、京东、苏宁易购等各大电商平台近日相继发布“月饼大数据”。透过这些大数据&#xff0c;我们来看看今年的“月饼消费”有哪些新趋势&#xff1f; 五仁稳居销量“老大哥” 五仁桂花、五仁肉松、五仁牛肉、五仁…

使用FuncT, TResult 委托实现API日志的记录

问题平常我们开发web api的时候&#xff0c;一般是需要记录api的输入输出信息&#xff0c;方便后续排查问题&#xff1b;那么我们一般怎么做的&#xff0c;一般是我们在一个公共地方的写个公共方法控制输入输出。这时候Func<T, TResult> 委托就派上用场。什么是FuncFunc&…

xencenter vgpu 看不见_有一种设计是“看不见,但感受得到”

设计源于生活&#xff0c;设计改变生活。在从业10余年之久的设计师刘洋来看&#xff0c;设计就是带着初心&#xff0c;不断去改变&#xff0c;去创造&#xff0c;去将更多设计的理念投射到时代的潮流中。刘洋认为设计不止是视觉感受&#xff0c;更重要的是融入人的情感&#xf…

数学告诉你家庭关系的奥秘

一直跟踪家庭关系可能非常困难。如果你父亲表弟的女儿刚刚生了一个小男孩&#xff0c;你们两个人怎样被相互介绍&#xff1f;谁是你的"曾曾姑母"&#xff1f;怎样发现你的"移去两次的第一代表亲"&#xff1f;幸运的是&#xff0c;一点儿数学逻辑可以帮助澄…

sql server2005 分页特性

在sql server 2005的新功能中&#xff0c;比较西黄分页功能&#xff0c;通过查询函数row_number over(order by field)实现是提取分页数据当页的记录&#xff0c;此功能原理上和临时表差不多&#xff0c;不过通过插叙语句操作就快捷多了&#xff0c;做了个demo&#xff0c;分页…

c#爬虫-1688官网自动以图搜图

背景在1688有个功能&#xff0c;就是上传图片&#xff0c;就可以找到类似的商品。如下网址 &#xff1a;https://www.1688.com/这时候&#xff0c;我们可以使用程序来代替&#xff0c;大批量的完成图片上传功能。实现思路1、找到图片上传接口post请求&#xff0c;form表单中有s…

php代码里加图片,php如何添加图片

php如何添加图片&#xff1f;php中插入图片的代码是什么&#xff1f;PHP插入图片&#xff0c;实际还是输出HTML代码比如&#xff1a;echo ;还可以直接用PHP生成图片显示出来php的gd库可以生成多种图像文件&#xff0c;如gif,png,jpg,wbmp,xpm等&#xff0c;下面来看一个生成正方…

matlab优化算法案例分析与应用_最优化计算与matlab实现(18)——粒子群优化算法——权重改进的粒子群算法...

参考资料《精通MATLAB最优化计算&#xff08;第二版&#xff09;》编程工具Matlab 2019a目录石中居士&#xff1a;最优化计算与Matlab实现——目录​zhuanlan.zhihu.com权重改进的粒子群算法在微粒群算法的可调整参数中&#xff0c;惯性权重 是最重要的参数&#xff0c;较大的 …

两个list怎么对比数据_基于日志的回放对比系统设计

‍‍‍‍‍‍点击关注“有赞coder”获取更多技术干货哦&#xff5e;作者&#xff1a;马力部门&#xff1a;新零售测试一、背景上半年公司的网关系统进行了重构&#xff0c;需要把零售业务已有的网关接口迁移到新网关上。这些接口每天都有成千上万次请求&#xff0c;为商家提供各…