C#系列之聊聊.Net Core的InMemoryCache

这两天在看.net core的in memory cache,这里记录一下用法,主要涉及MemoryCache的Get/Set/Expire/Flush。
首先我们先用dotnet命令创建一个mvc的项目,这里我们将使用postman来请求server,

1
dotnet new MVC

因为我们要用到 Microsoft.Extensions.Caching.Memory这个nuget包,所以需要添加引用,用VsCode(或任何编辑器)打开刚才建的mvc项目路径下的*.csproj文件,在这里我的是cache.csproj,找到这个标签,添加如下代码:


<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.0.0"/>

注意版本号可能不一样,我用的是.net core 2.0.
之后我们需要注册cache服务,打开Startup.cs文件,找到ConfigureServices方法,添加如下代码:


services.AddMemoryCache();

ConfigureServices方法看起来应该是这样:


public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddMvc();
}

之后我们就可以在controller里通过构造注入的方式使用InMemoryCache啦。
打开HomeController或者自己新建一个Controller,在修改构造方法


private IMemoryCache _cache;
public HomeController(IMemoryCache cache)
{
this._cache = cache;
}

先来看看MemoryCache的定义:


Constructors:
MemoryCache(IOptions)
Properties:
Count(Gets the count of the current entries for diagnostic purposes.)
Methods:
Compact(Double)
CreateEntry(Object)
Dispose()
Dispose(Boolean)
Finalize()
Remove(Object)
TryGetValue(Object, Object)
Extension Methods:
Get(IMemoryCache, Object)
Get(IMemoryCache, Object)
GetOrCreate(IMemoryCache, Object, Func)
GetOrCreateAsync(IMemoryCache, Object, Func>)
Set(IMemoryCache, Object, TItem)
Set(IMemoryCache, Object, TItem, MemoryCacheEntryOptions)
Set(IMemoryCache, Object, TItem, IChangeToken)
Set(IMemoryCache, Object, TItem, DateTimeOffset)
Set(IMemoryCache, Object, TItem, TimeSpan)
TryGetValue(IMemoryCache, Object, TItem)

我们用到的大部分都是 扩 展 方 法,这是一个奇怪的现象,但这不是这篇文章讨论的重点,这里会使用到


TryGetValue(Object, Object)
Set<TItem>(IMemoryCache, Object, TItem, MemoryCacheEntryOptions)

这两个方法,来Get/Set/Expire缓存项。

首先我们来添加一个get的webapi:


[HttpGet("cache/{key}")]
public IActionResult GetCache(string key)
{
object result = new object();
_cache.TryGetValue(key, out result);
return new JsonResult(result);
}

它接受一个key作为参数,如果找到则返回找到的值,若找不到则返回空
现在我们可以在命令行里输入

1
2
dotnet restore
dotnet run

来启动web项目,之后我们可以通过

1
http://localhost:5000/cache/{key}

这个url来访问cache,此时cache还没有值
640?wx_fmt=png
因为此时我们还没有set值。
接下来添加一个Set方法,在添加之前,我们先来看一下MemoryCacheEntryOptions的定义。

Constructors:
MemoryCacheEntryOptions()

Properties:
AbsoluteExpiration
AbsoluteExpirationRelativeToNow
ExpirationTokens
PostEvictionCallbacks
Priority
Size
SlidingExpiration

Extension Methods:
AddExpirationToken(MemoryCacheEntryOptions, IChangeToken)
RegisterPostEvictionCallback(MemoryCacheEntryOptions, PostEvictionDelegate)
RegisterPostEvictionCallback(MemoryCacheEntryOptions, PostEvictionDelegate, Object)
SetAbsoluteExpiration(MemoryCacheEntryOptions, DateTimeOffset)
SetAbsoluteExpiration(MemoryCacheEntryOptions, TimeSpan)
SetPriority(MemoryCacheEntryOptions, CacheItemPriority)
SetSize(MemoryCacheEntryOptions, Int64)
SetSlidingExpiration(MemoryCacheEntryOptions, TimeSpan)

这里有几个概念:
AbsoluteExpiration
代表了绝对绝对超时时间,在一定时间后必定超时(比如15分钟)

SlidingExpiration
代表了滑动超时时间(我自己翻译的。。),滑动的意思就是假如你设置了SlidingExpiration超时时间为5分钟,如果在5分钟里,有新的请求来获取这个cached item,那么这个5分钟会重置,直到超过5分钟没有请求来,才超时

CacheItemPriority
这是一个枚举,代表了缓存的优先级,默认值为Normal,如果设置为NeverRemove则一直不超时。


High   
Low
NeverRemove
Normal

RegisterPostEvictionCallback
这是个方法需要传一个回调,在缓存项被移除(超时)的时候触发回调。

接着我们来添加一个Set方法,并且为它添加一个canceltoken,以便我们能够手动控制强制清空缓存。


private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
[HttpPost("cache/")]
public IActionResult SetCache([FromBody]CacheItem item)
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(5))
.RegisterPostEvictionCallback(DependentEvictionCallback, null)
.AddExpirationToken(new CancellationChangeToken(cancellationTokenSource.Token));
_cache.Set(item.key, item.value, cacheEntryOptions);
return Ok();
}

然后我们就可以用postman的post请求来Set缓存了,地址是:

1
http://localhost:5000/cache

640?wx_fmt=png

接下来我们来添加一个flush api,我们能够手动清空缓存。这里我们利用了上面在Set时添加的cancellationTokenSource


[HttpGet("cache/flush")]
public IActionResult Flush()
{
cancellationTokenSource.Cancel();
return Ok();
}

访问地址:


http://localhost:5000/cache/flush

调用这个api会发现在console里有一行输出


Parent entry was evicted. Reason: TokenExpired, Key: a.

可以在多个缓存项中添加同一个token,达到同时清除多个缓存项的目的。

遇到的坑:
1.token不work的问题.
我在最初实现的时候,加了一个token,是这么写的


private CancellationTokenSource cancellationTokenSource;
public HomeController(IMemoryCache cache)
{
this._cache = cache;
cancellationTokenSource = new CancellationTokenSource();
}
[HttpGet("cache/flush")]
public IActionResult Flush()
{
cancellationTokenSource.Cancel();
return Ok();
}

然后发现调用flush一直不生效,cache并没有被清掉,很纳闷,以为我的token方法用的有问题。
直到我换成了下面的代码,大家体会一下。


private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
public HomeController(IMemoryCache cache)
{
this._cache = cache;
}
[HttpGet("cache/flush")]
public IActionResult Flush()
{
cancellationTokenSource.Cancel();
return Ok();
}

仅仅是一个static的问题,就产生了不一样的结果,这是因为每次httprequest过来,都会启动一个新线程去响应它,因此在set的时候加进去的那个token,并不是flush请求过来的token,因为又调用了一次构造方法,生成了一个新的CancellationTokenSource对象,因此调用token.Cancel()方法必然会失效,因此改成了static,让每次请求的都是同一个token,这样就不会造成不同token导致的Cancel方法不work的问题,清空cache也就能正常工作了。

2.RegisterPostEvictionCallback重复触发的问题

RegisterPostEvictionCallback不仅仅在缓存超时的时候触发,也会在缓存被替换(更新)的时候触发,在PostEvictionDelegate有一个参数为EvictionReason指明了缓存项被移除的原因


public delegate void PostEvictionDelegate(object key, object value, EvictionReason reason, object state);

EvictionReason
None = 0,
Removed = 1,  缓存项被Remove()方法移除
Replaced = 2,  缓存项被更新
Expired = 3,  缓存项超时
TokenExpired = 4, 缓存由token触发超时
Capacity = 5 缓存空间不足

因此我们需要在callback里根据需要判断缓存是因为什么原因被移除,才能避免意外的回调触发。

原文地址: https://www.cnblogs.com/xiandnc/p/9517017.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

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

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

相关文章

P1412-经营与开发【dp】

正题 题目链接:https://www.luogu.com.cn/problem/P1412 题目大意 nnn个地点&#xff0c;有一个能力值为www的稿子 如果地点iii是资源型的&#xff0c;那么可以选择获得ai∗wa_i*wai​∗w的价值&#xff0c;且ww∗(1−k100)ww*(1-\frac{k}{100})ww∗(1−100k​)如果地点iii是…

纪中在家培训总结(2020.2.1~2020.2.24)

前言 因为新型冠状病毒&#xff08;疫情情况&#xff09;的原因&#xff0c;纪中培训改为在家培训&#xff0c;一天的进度变成了两天甚至三天的进度QAQ&#xff0c;但我还是想说&#xff1a;武汉加油&#xff01;中国加油&#xff01; 这次培训总结没啥好写&#xff0c;请勿嘲…

CF1137F Matches Are Not a Child‘s Play(树上数据结构问题、树链剖分+ODT)

Description 一棵 n 个点的树&#xff0c;点权最初为 1 ∼ n 的排列。 定义一个删点过程&#xff1a;每次找到权值最小的叶子&#xff0c;删去它以及连接的边&#xff0c;重复这个过程直到剩下一个点&#xff0c;然后删去最后的点。 处理 q 个询问&#xff1a; 将一个点 x 的…

小石的签到题

链接&#xff1a; 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld题目描述 输入描述: 共一行&#xff0c;输入一个数 n 。 输出描述: 共一行&#xff0c;输出 “Shi” 或 “Yang”&…

值类型、引用类型和泛型的前世今生

值类型、引用类型和泛型多语言咱们先不说主题&#xff0c;先说说CLR支持多语言。 .net有个非常强大的特点&#xff0c;那就是跨语言&#xff0c;支持很多语言&#xff0c;比如C#、J#等。先来个图看一看C# J# VB 等等等

P3247-[HNOI2016]最小公倍数【分块,并查集】

正题 题目链接:https://www.luogu.com.cn/problem/P3247 题目大意 nnn个点mmm条边&#xff0c;每条边有(x,y,a,b)(x,y,a,b)(x,y,a,b)。qqq次询问(x′,y′,a′,b′)(x,y,a,b)(x′,y′,a′,b′)表示询问是否存在一条x′−>y′x->yx′−>y′的路径使得路径上amaxa′,bma…

【DP】奖励卡(jzoj 3937)

奖励卡 jzoj 3937 题目大意 现在有一场比赛&#xff0c;想观看的人要提交申请&#xff0c;现在有x个人提交后得到两个号&#xff0c;y个人提交后得到一个号&#xff0c;有n轮抽号&#xff0c;每一轮抽一个号&#xff08;概率相等&#xff09;&#xff0c;这个号的所有者不参…

CF526G Spiders Evil Plan(树上最优性问题、倍增+线段树)

Description 一棵 n 个结点的树&#xff0c;有正边权。 用 y 条链覆盖这棵树&#xff0c;满足&#xff1a; 所有链连通&#xff08;有重点即算作相连&#xff09;点 x 被覆盖被覆盖的边的权值和尽可能大 q 次给出 x, y&#xff0c;询问最大边权和&#xff0c;强制在线。 n, q…

CAP带你轻松玩转ASP.NETCore消息队列

CAP是什么&#xff1f;CAP是由我们园子里的杨晓东大神开发出来的一套分布式事务的决绝方案&#xff0c;是.Net Core Community中的第一个千星项目&#xff08;目前已经1656 Start&#xff09;&#xff0c;具有轻量级、易使用、高性能等特点。https://github.com/dotnetcore/CAP…

装备合成

链接&#xff1a; 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld题目描述 输入描述: 输入包含t组数据 第一行一个整数t 接下来t行每行两个整数x,y 输出描述: 每组数据输出一行一个…

P4161-[SCOI2009]游戏【dp】

正题 题目链接:https://www.luogu.com.cn/problem/P4161 题目大意 一个1∼n1\sim n1∼n的排列&#xff0c;f(x)f(x)f(x)表示在置换xxx下置换多少次才能回到原来的排列&#xff0c;求在所有置换下f(x)f(x)f(x)的所有可能的值的数量。 解题思路 一个置换的fff值就是这个置换的…

【spfa】假期计划(jzoj 3936)

假期计划 jzoj 3936 题目大意 给你一个有向图&#xff08;n,m⩽20000n,m\leqslant 20000n,m⩽20000&#xff09;&#xff0c;现在有一些作为枢纽的点&#xff0c;且保证每一条边的两个点至少有一个是枢纽点&#xff0c;现在给q个询问&#xff0c;问某一个点到另一个点的最短…

CF650E Clockwork Bomb(树上构造类问题、并查集)

Description 给出两棵 n 结点的有标号树。 每次操作删去第一棵树的一条边&#xff0c;再加上一条边&#xff0c;需要保证此时还是一棵树。 构造一种操作序列&#xff0c;将第一棵树变成第二棵树&#xff0c;使得操作数最小。 n ≤ 51055 \times 10^55105 Solution 显然&…

微软必应从.NET Core 2.1获得了性能提升

据微软工程师Mukul Sabharwal介绍&#xff0c;在将微软搜索引擎必应迁移到.NET Core 2.1之后&#xff0c;内部服务延迟降低了34%&#xff0c;这主要归功于.NET社区贡献的改进。按照Sabharwal的说法&#xff0c;.NET Core的多项改进贡献了大部分的性能提升&#xff0c;包括字符串…

阶乘

链接&#xff1a; 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld题目描述 给定一个正整数 p 求一个最小的正整数 n&#xff0c;使得 n! 是 p 的倍数 输入描述: 第一行输入一个正整数…

P2151-[SDOI2009]HH去散步【矩阵乘法】

正题 题目链接:https://www.luogu.com.cn/problem/P2151 题目大意 nnn个点mmm条边的一张无向图&#xff0c;走过一条边后下一次就不能再走这条&#xff0c;求AAA到BBB之间有多少长度为ttt的路径。 解题思路 因为有不能再走同一条的限制&#xff0c;所以不能直接裸上矩乘&…

IQ测试(jzoj 5048)

IQ测试 jzoj 5048 题目大意 给出一个序列a&#xff0c;然后有m个询问&#xff0c;每个询问给出一个序列&#xff0c;问这个序列是否可以由序列a删掉一些数得到的 输入样例 7 1 5 4 5 7 8 6 4 5 1 5 5 8 6 3 2 2 2 3 5 7 8 4 1 5 7 4输出样例 TAK NIE TAK NIE数据范围 对…

CF1088F Ehab and a weird weight formula(树上最优性问题、贪心+倍增)

Description 给出一棵 n 个结点的树&#xff0c;点 i 有正权值 wiw_iwi​&#xff0c;wiw_iwi​ 互不相同。 除了权值最小的点&#xff0c;保证每个点 u 都有一个邻点 v 使得 wvw_vwv​ < wuw_uwu​。 构造一棵树&#xff0c;最小化代价&#xff1a; 对于每个点 u&#xf…

搭建基于云端的中间层以支持跨平台的智能视觉服务

不断演进的应用场景初级应用场景—宅在家里场景&#xff1a;Bob同学有一天在网上看到了一张建筑物的图片&#xff0c;大发感慨&#xff1a;"好漂亮啊&#xff01;这是哪里&#xff1f;我要去亲眼看看&#xff01;"Bob同学不想问别人&#xff0c;可笑的自尊心让他觉得…

YbtOJ#20235-[冲刺NOIP2020模拟赛Day9]公共序列【dp】

正题 题目链接:https://www.ybtoj.com.cn/contest/66/problem/3 题目大意 给出两个字符串A,BA,BA,B&#xff0c;求它们的最长公共子序列。 解题思路 先考虑朴素的dpdpdp&#xff0c;设fi,jf_{i,j}fi,j​表示到AAA的第iii个&#xff0c;BBB的第jjj个时候的最长公共子序列长度…