关于我

作者博客|文章首发

缓存基础知识

缓存可以减少生成内容所需的工作,从而显著提高应用程序的性能和可伸缩性。 缓存最适用于不经常更改的 数据,生成 成本很高。 通过缓存,可以比从数据源返回的数据的副本速度快得多。 应该对应用进行编写和测试,使其 永不 依赖于缓存的数据。

ASP.NET Core 支持多个不同的缓存。 最简单的缓存基于 IMemoryCache。 IMemoryCache 表示存储在 web 服务器的内存中的缓存。 在服务器场上运行的应用 (多台服务器) 应确保会话在使用内存中缓存时处于粘滞状态。 粘滞会话确保来自客户端的后续请求都将发送到相同的服务器。

内存中缓存可以存储任何对象。 分布式缓存接口仅限 byte[] 。 内存中和分布式缓存将缓存项作为键值对。

缓存指南

  • 代码应始终具有回退选项,以获取数据,而 是依赖于可用的缓存值。
  • 缓存使用稀有资源内存,限制缓存增长:
    • 不要 使用外部 输入作为缓存键。
    • 使用过期限制缓存增长。
    • 使用 SetSize、Size 和 SizeLimit 限制缓存大小]。 ASP.NET Core 运行时不会根据内存 压力限制缓存 大小。 开发人员需要限制缓存大小。

使用

DI注入

创建一个NetCore控制台项目,进行缓存的项目演示。

控制台项目只有一个初始化的Program.cs文件。基于NetCore进行项目编码,每一步就是创建一个基础模板,使用依赖注入的方式。

nuget install Microsoft.Extensions.Hosting
  public static class Program
{
static async void Main(string[] args)
{
var builder = new HostBuilder().ConfigureServices((context, service) =>
{ }); await builder.RunConsoleAsync();
}
}

注入缓存服务,控制台需要下载库 Microsoft.Extensions.Caching.Memory

nuget install Microsoft.Extensions.Caching.Memory
  public static class Program
{
static async void Main(string[] args)
{
var builder = new HostBuilder().ConfigureServices((context, service) =>
{
service.AddMemoryCache(); service.AddScoped<CacheService>();//实际测试服务 service.AddHostedService<BackgroundJob>();//后台执行方法
}); await builder.RunConsoleAsync();
}
}

后台服务

public class BackgroundJob : IHostedService
{
private readonly CacheService _cacheService; public BackgroundJob(CacheService cacheService)
{
_cacheService = cacheService;
} public Task StartAsync(CancellationToken cancellationToken)
{
_cacheService.Action(); return Task.CompletedTask;
} public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

MemoryCache使用总结

通过构造函数自动注入IMemoryCache

public class CacheService
{
private readonly IMemoryCache _memoryCache; public CacheService(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
}

最基本的使用

Set方法根据Key设置缓存,默认缓存不过期

Get方法根据Key取出缓存

/// <summary>
/// 缓存设置
/// </summary>
public void BaseCache()
{
string cacheKey = "timestamp";
//set cache
_memoryCache.Set(cacheKey, DateTime.Now.ToString()); //get cache
Console.WriteLine(_memoryCache.Get(cacheKey));
}

IMemoryCache提供一些好的语法糖供开发者使用,具体内容看下方文档

/// <summary>
/// 特殊方法的使用
/// </summary>
public void ActionUse()
{
//场景-如果缓存存在,取出。如果缓存不存在,写入
//原始写法
string cacheKey = "timestamp";
if (_memoryCache.Get(cacheKey) != null)
{
_memoryCache.Set(cacheKey, DateTime.Now.ToString());
}
else
{
Console.WriteLine(_memoryCache.Get(cacheKey));
} //新写法
var dataCacheValue = _memoryCache.GetOrCreate(cacheKey, entry =>
{
return DateTime.Now.ToString();
});
Console.WriteLine(dataCacheValue); //删除缓存
_memoryCache.Remove(cacheKey); //场景 判断缓存是否存在的同时取出缓存数据
_memoryCache.TryGetValue(cacheKey, out string cacheValue);
Console.WriteLine(cacheValue); }

缓存过期策略

设置缓存常用的方式主要是以下二种

  1. 绝对到期(指定在一个固定的时间点到期)
  2. 滑动到期(在一个时间长度内没有被命中则过期)
  3. 组合过期 (绝对过期+滑动过期)

绝对到期

过期策略 5秒后过期

//set absolute cache
string cacheKey = "absoluteKey";
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), TimeSpan.FromSeconds(5)); //get absolute cache
for (int i = 0; i < 6; i++)
{
Console.WriteLine(_memoryCache.Get(cacheKey));
Thread.Sleep(1000);
}

滑动到期

过期策略 2秒的滑动过期时间,如果2秒内有访问,过期时间延后。当2秒的区间内没有访问,缓存过期

//set slibing cache
string cacheSlibingKey = "slibingKey";
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.SlidingExpiration = TimeSpan.FromSeconds(2); _memoryCache.Set(cacheSlibingKey, DateTime.Now.ToString(), options); //get slibing cache
for (int i = 0; i < 2; i++)
{
Console.WriteLine(_memoryCache.Get(cacheSlibingKey));
Thread.Sleep(1000);
}
for (int i = 0; i < 2; i++)
{
Thread.Sleep(2000);
Console.WriteLine(_memoryCache.Get(cacheSlibingKey));
}

组合过期

过期策略

6秒绝对过期+2秒滑动过期

满足任意一个缓存都将失效

string cacheCombineKey = "combineKey";
MemoryCacheEntryOptions combineOptions = new MemoryCacheEntryOptions();
combineOptions.SlidingExpiration = TimeSpan.FromSeconds(2);
combineOptions.AbsoluteExpiration = DateTime.Now.AddSeconds(6); _memoryCache.Set(cacheCombineKey, DateTime.Now.ToString(), combineOptions); //get slibing cache
for (int i = 0; i < 2; i++)
{
Console.WriteLine(_memoryCache.Get(cacheCombineKey));
Thread.Sleep(1000);
} for (int i = 0; i < 6; i++)
{
Thread.Sleep(2000);
Console.WriteLine(i+"|" + _memoryCache.Get(cacheCombineKey));
} Console.WriteLine("------------combineKey End----------------");

缓存状态变化事件

当缓存更新、删除时触发一个回调事件,记录缓存变化的内容。

/// <summary>
/// cache状态变化回调
/// </summary>
public void CacheStateCallback()
{
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.AbsoluteExpiration = DateTime.Now.AddSeconds(3
);
options.RegisterPostEvictionCallback(MyCallback, this); //show callback console
string cacheKey = "absoluteKey";
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), options); Thread.Sleep(500);
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), options); _memoryCache.Remove(cacheKey); } private static void MyCallback(object key, object value, EvictionReason reason, object state)
{
var message = $"Cache entry state change:{key} {value} {reason} {state}";
((CacheService)state)._memoryCache.Set("callbackMessage", message); Console.WriteLine(message);
}

缓存依赖策略

设置一个缓存A

设置一个缓存B,依赖于缓存A 如果缓存A失效,缓存B也失效

/// <summary>
/// 缓存依赖策略
/// </summary>
public void CacheDependencyPolicy()
{
string DependentCTS = "DependentCTS";
string cacheKeyParent = "CacheKeys.Parent";
string cacheKeyChild = "CacheKeys.Child"; var cts = new CancellationTokenSource();
_memoryCache.Set(DependentCTS, cts); //创建一个cache策略
using (var entry = _memoryCache.CreateEntry(cacheKeyParent))
{
//当前key对应的值
entry.Value = "parent" + DateTime.Now; //当前key对应的回调事件
entry.RegisterPostEvictionCallback(MyCallback, this); //基于些key创建一个依赖缓存
_memoryCache.Set(cacheKeyChild, "child" + DateTime.Now, new CancellationChangeToken(cts.Token));
} string ParentCachedTime = _memoryCache.Get<string>(cacheKeyParent);
string ChildCachedTime = _memoryCache.Get<string>(cacheKeyChild);
string callBackMsg = _memoryCache.Get<string>("callbackMessage");
Console.WriteLine("第一次获取");
Console.WriteLine(ParentCachedTime + "|" + ChildCachedTime + "|" + callBackMsg); //移除parentKey
_memoryCache.Get<CancellationTokenSource>(DependentCTS).Cancel();
Thread.Sleep(1000); ParentCachedTime = _memoryCache.Get<string>(cacheKeyParent);
ChildCachedTime = _memoryCache.Get<string>(cacheKeyChild);
callBackMsg = _memoryCache.Get<string>("callbackMessage");
Console.WriteLine("第二次获取");
Console.WriteLine(ParentCachedTime + "|" + ChildCachedTime + "|" + callBackMsg);
}

参考资料

AspNetCore中的缓存内存

.NetCore缓存篇之MemoryCache

Asp.Net Core 轻松学-在.Net Core 使用缓存和配置依赖策略

拥抱.NET Core系列:MemoryCache 缓存过期

推荐阅读

Redis工具收费后新的开源已出现

GitHub上Star最高的工程师技能图谱

中国程序员最容易发错的单词

推荐!!! Markdown图标索引网站

最后

本文到此结束,希望对你有帮助

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

更多精彩技术文章汇总在我的 公众号【程序员工具集】,持续更新,欢迎关注订阅收藏。

NetCore的缓存使用详例的更多相关文章

  1. Redis for Windows(C#缓存)配置文件详解

    Redis for Windows(C#缓存)配置文件详解   前言 在上一篇文章中主要介绍了Redis在Windows平台下的下载安装和简单使用http://www.cnblogs.com/aehy ...

  2. 《深入理解mybatis原理6》 MyBatis的一级缓存实现详解 及使用注意事项

    <深入理解mybatis原理> MyBatis的一级缓存实现详解 及使用注意事项 0.写在前面   MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓 ...

  3. 浏览器 HTTP 协议缓存机制详解

    最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control.为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里带了 etag, ...

  4. nginx平台初识(二) 浏览器 HTTP 协议缓存机制详解

    1.缓存的分类 缓存分为服务端侧(server side,比如 Nginx.Apache)和客户端侧(client side,比如 web browser). 服务端缓存又分为 代理服务器缓存 和 反 ...

  5. PHP缓存机制详解

    一,PHP缓存机制详解 我们可以使用PHP自带的缓存机制来完成页面静态化,但是仅靠PHP自身的缓存机制并不能完美的解决页面静态化,往往需要和其他静态化技术(通常是伪静态技术)结合使用. output ...

  6. 二,PHP缓存机制详解

    一,PHP缓存机制详解 我们可以使用PHP自带的缓存机制来完成页面静态化,但是仅靠PHP自身的缓存机制并不能完美的解决页面静态化,往往需要和其他静态化技术(通常是伪静态技术)结合使用. output ...

  7. hibernate缓存机制详解

    hiberante面试题—hibernate缓存机制详解   这是面试中经常问到的一个问题,可以按照我的思路回答,准你回答得很完美.首先说下Hibernate缓存的作用(即为什么要用缓存机制),然后再 ...

  8. Robocopy.exe使用详例

    Robocopy.exe使用详例           Robocopy.exe 是 微软在Windows server 2003 Resource Kit Tools 里面提供的程序来做备份的.Vis ...

  9. 浏览器 HTTP 协议缓存机制详解--网络缓存决策机制流程图

    1.缓存的分类 2.浏览器缓存机制详解 2.1 HTML Meta标签控制缓存 2.2 HTTP头信息控制缓存 2.2.1 浏览器请求流程 2.2.2 几个重要概念解释 3.用户行为与缓存 4.Ref ...

随机推荐

  1. 微软收购 GitHub

    微软收购 GitHub 微软收购 GitHub震惊业界:引发开发者信任问题 https://news.cnblogs.com/n/598432/ GitLab refs xgqfrms 2012-20 ...

  2. pub package all in one

    pub package all in one best practice The pubspec file https://dart.dev/tools/pub/pubspec demo name: ...

  3. ES6 Generator vs ES6 async/await

    ES6 Generator vs ES6 async/await next yield promise refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允 ...

  4. H5 直播 & App 直播

    H5 直播 & App 直播 polyv 直播 https://github.com/polyv 宝利威 直播 https://www.polyv.net/live/ SDK https:// ...

  5. subline3 如何设置es6高亮

    步骤: 1.操作Ctrl+Shift+P , 然后在弹出的框内输入Package Control: in,2.选择Package Control: install package,3.等待再次弹出输入 ...

  6. 比起USDT,我为什么建议你选择USDN

    2018年1月16日,USDT(泰达币)进入了很多人的视野.因为在这一天,在全球价值排名前50的加密货币中,包括比特币.莱特币以及以太坊在内的大多数的数字虚拟加密货币都遭遇了价格大幅下跌,只有泰达币价 ...

  7. 【DB宝19】在Docker中使用MySQL高可用之MHA

    目录 一.MHA简介和架构 1.1 MHA简介 1.2 MHA工具包的组成 1.3 MHA架构 二.准备MHA环境 2.1 下载MHA镜像 2.2 编辑yml文件,创建MHA相关容器 2.3 安装do ...

  8. pytorch resnet实现

    官方github上已经有了pytorch基础模型的实现,链接 但是其中一些模型,尤其是resnet,都是用函数生成的各个层,自己看起来是真的难受! 所以自己按照caffe的样子,写一个pytorch的 ...

  9. redis源码之SDS

    1:SDS介绍 我们在redis中执行命令 set key name 的时候,key和name都是字符串类型,而且字符串(string)在redis中是会经常用到的类型,那redis是如何保存字符串的 ...

  10. 无所不能的Embedding7 - 探索通用文本表达[FastSent/InferSent/GenSen/USE]

    在4/5章我们讨论过用skip-thought,quick-thought任务来进行通用文本向量提取,当时就有一个疑问为什么用Bookcorpus这种连续文本,通过预测前一个和后一个句子的方式得到的文 ...