ASP.NET Core - 缓存之内存缓存(下)

这篇具有很好参考价值的文章主要介绍了ASP.NET Core - 缓存之内存缓存(下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

话接上篇 ASP.NET Core - 缓存之内存缓存(上),所以这里的目录从 2.4 开始。

2.4 MemoryCacheEntryOptions

MemoryCacheEntryOptions 是内存缓存配置类,可以通过它配置缓存相关的策略。除了上面讲到的过期时间,我们还能够设置下面这些:

  • 设置缓存优先级。
  • 设置在从缓存中逐出条目后调用的 PostEvictionDelegate。
    回调在与从缓存中删除项的代码不同的线程上运行。
  • 限制缓存大小
var memoryCacheEntryOption = new MemoryCacheEntryOptions();
memoryCacheEntryOption.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3);
// 缓存优先级,Low, Normal, High, NeverRemove,Normal是默认值,与缓存删除时的策略有关
memoryCacheEntryOption.SetPriority(CacheItemPriority.Normal);
// 注册缓存项删除回调事件
memoryCacheEntryOption.RegisterPostEvictionCallback(PostEvictionDelegate);
_cache.Set(CacheKey, cacheValue, memoryCacheEntryOption);

public void PostEvictionDelegate(object cacheKey, object cacheValue, EvictionReason evictionReason, object state)
{
	var memoryCache = (IMemoryCache)state;

	Console.WriteLine($"Entry {cacheKey}:{cacheValue} was evicted: {evictionReason}.");
}

ASP.NET Core - 缓存之内存缓存(下)

缓存大小限制要配合 MemoryCache 实例的配置来使用。MemoryCache 实例可以选择指定并强制实施大小限制。 缓存大小限制没有定义的度量单位,因为缓存没有度量条目大小的机制。 如果设置了缓存大小限制,则所有条目都必须指定大小。 ASP.NET Core 运行时不会根据内存压力限制缓存大小。 由开发人员限制缓存大小。 指定的大小采用开发人员选择的单位。

例如:

  • 如果 Web 应用主要缓存字符串,则每个缓存条目的大小可以是字符串长度。
  • 应用可以将所有条目的大小指定为 1,大小限制是条目计数。
    如果未设置 SizeLimit,则缓存会无限增长。 系统内存不足时,ASP.NET Core 运行时不会剪裁缓存。 应用必须构建为:
    • 限制缓存增长。
    • 在可用内存受限时调用 Compact 或 Remove。

这里的意思是,缓存大小没有单位,我们可以设置一个总的大小,然后为每个缓存条目设置一个大小。如果没有设置大小的情况下,缓存可能会无限增长,直至用完服务器上的所有内存。

// 我们可以在进行内存缓存注册的时候设置缓存大小限制
services.AddMemoryCache(options =>
{
	options.SizeLimit = 1024;
});

// 之后设定每个缓存项的大小,可根据开发人员的判断设置,例如这里无论多大都设置为 1,则最多有 1024 个缓存项
memoryCacheEntryOption.SetSize(1);
_cache.Set(CacheKey, cacheValue, memoryCacheEntryOption);

2.5 缓存清理

缓存到期后不会在后台自动清理。 没有计时器可以主动扫描缓存中的到期项。 而缓存上的任何活动(Get、Set、Remove)都可触发在后台扫描到期项。 如果使用了CancellationTokenSource ,则其计时器 (CancelAfter) 也会删除条目并触发扫描到期项,这个是下面要讲到的。

除了在对缓存进行操作时,会触发对相应的缓存项进行过期检查之外,我们还可以通过手动调用 Remove 方法和 Compact 方法对缓存进行清理。

_cache.Remove(cacheKey);
_cache.Compact(.25);

Compact 方法会尝试按以下顺序删除指定百分比的缓存:

  • 所有到期项。
  • 按优先级排列的项。 首先删除最低优先级的项。
  • 最近最少使用的对象。
  • 绝对到期时间最短的项。
  • 可调到期时间最短的项。

永远不会删除优先级为 NeverRemove 的固定项。 上面的代码的作用就是删除cacheKey对于的缓存项,并调用 Compact 以删除 25% 的缓存条目。

2.6 缓存组

缓存项的过期策略除了上面讲到的过期时间的设置之外,还可以通过 CancellationChangeToken 来控制,通过它可以同时控制多个缓存对象的过期策略,实现相关的缓存同时过期,构成一个组的概念。

以下为示例代码:

首先先定义两个方法,将缓存设置和缓存读取分开:

public interface ICacheService
{
	public void PrintDateTimeNow();

	public void SetGroupDateTime();

	public void PrintGroupDateTime();
}

public class CacheService : ICacheService 
{
	public const string CacheKey = "CacheTime";
	public const string DependentCancellationTokenSourceCacheKey = "DependentCancellationTokenSource";
	public const string ParentCacheKey = "Parent";
	public const string ChildCacheKey = "Chlid";
	private readonly IMemoryCache _cache;
	public CacheService(IMemoryCache memoryCache)
	{
		_cache = memoryCache;
	}

	public void PrintDateTimeNow()
	{
		var time = DateTime.Now;
		if (!_cache.TryGetValue(CacheKey, out DateTime cacheValue))
		{
			cacheValue = time;
			// 设置绝对过期时间
			// 两种实现的功能是一样的,只是时间设置的方式不同而已
			// 传入的是 AbsoluteExpirationRelativeToNow, 相对当前的绝对过期时间,传入时间差,会根据当前时间算出绝对过期时间
			// _cache.Set(CacheKey, cacheValue, TimeSpan.FromSeconds(2));
			// 传入的是 AbsoluteExpiration,绝对过期时间,传入一个DateTimeOffset对象,需要明确的指定具体的时间
			// _cache.Set(CacheKey, cacheValue, DateTimeOffset.Now.AddSeconds(2));

			//var memoryCacheEntryOption = new MemoryCacheEntryOptions();
			//// 滑动过期时间是一个相对时间
			//memoryCacheEntryOption.SlidingExpiration = TimeSpan.FromSeconds(3);
			//_cache.Set(CacheKey, cacheValue, memoryCacheEntryOption);

			var memoryCacheEntryOption = new MemoryCacheEntryOptions();
			memoryCacheEntryOption.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3);
			// 缓存优先级,Low, Normal, High, NeverRemove,Normal是默认值,与缓存删除时的策略有关
			memoryCacheEntryOption.SetPriority(CacheItemPriority.Normal);
			memoryCacheEntryOption.RegisterPostEvictionCallback(PostEvictionDelegate);
			// 之后设定每个缓存项的大小,可根据开发人员的判断设置,例如这里无论多大都设置为 1,则最多有 1024 个缓存项
			memoryCacheEntryOption.SetSize(1);
			_cache.Set(CacheKey, cacheValue, memoryCacheEntryOption);
		}
		time = cacheValue;

		Console.WriteLine("缓存时间:" + time.ToString("yyyy-MM-dd HH:mm:ss"));
		Console.WriteLine("当前时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
	}

	public void PostEvictionDelegate(object cacheKey, object cacheValue, EvictionReason evictionReason, object state)
	{
		var memoryCache = (IMemoryCache)state;

		Console.WriteLine($"Entry {cacheKey}:{cacheValue} was evicted: {evictionReason}.");
	}

	public void SetGroupDateTime()
	{
		// 这里为了将 CancellationTokenSource 保存起来,以便在外部可以获取得到
		var cancellationTokenSource = new CancellationTokenSource();
		_cache.Set(
			DependentCancellationTokenSourceCacheKey,
			cancellationTokenSource);

		using var parentCacheEntry = _cache.CreateEntry(ParentCacheKey);

		parentCacheEntry.Value = DateTime.Now;

		Task.Delay(TimeSpan.FromSeconds(1)).Wait();

		_cache.Set(
			ChildCacheKey,
			DateTime.Now,
			new CancellationChangeToken(cancellationTokenSource.Token));
	}

	public void PrintGroupDateTime()
	{
	   if(_cache.TryGetValue(ParentCacheKey, out DateTime parentCacheDateTime))
		{
			Console.WriteLine("ParentDateTime:" + parentCacheDateTime.ToString("yyyy-MM-dd HH:mm:ss"));
		}
		else
		{
			Console.WriteLine("ParentDateTime is canceled");
		}

		if (_cache.TryGetValue(ChildCacheKey, out DateTime childCacheDateTime))
		{
			Console.WriteLine("ChildDateTime:" + childCacheDateTime.ToString("yyyy-MM-dd HH:mm:ss"));
		}
		else
		{
			Console.WriteLine("ChildDateTime is canceled");
		}
	}
}

之后改造一下入口文件中的测试代码:

var service = host.Services.GetRequiredService<ICacheService>();
service.SetGroupDateTime();

service.PrintGroupDateTime();

service.PrintGroupDateTime();

var cache = host.Services.GetRequiredService<IMemoryCache>();
var cancellationTokenSource = cache.Get<CancellationTokenSource>(CacheService.DependentCancellationTokenSourceCacheKey);
cancellationTokenSource.Cancel();

service.PrintGroupDateTime();

从控制台输出可以看得到前两次缓存获取正常,当调用 CancellationTokenSource.Cancel() 方法取消请求之后,缓存过期了。

ASP.NET Core - 缓存之内存缓存(下)

如果使用 CancellationTokenSource,则允许将多个缓存条目作为一个组逐出。 使用上述代码中的 using 模式,在 using 范围内创建的缓存条目会继承触发器和到期设置。不过这种方式只有 using 范围的缓存项和 using 范围内使用 CancellationTokenSource 的缓存项可以构成一个组,如果范围内还有其他的缓存项,是不算在一个组内的。

ASP.NET Core - 缓存之内存缓存(下)

如果要把多个缓存项全部纳入一个组,还可以用以下的方式:

_cache.Set(ParentCacheKey,
	DateTime.Now,
	new CancellationChangeToken(cancellationTokenSource.Token));

_cache.Set(
	ChildCacheKey,
	DateTime.Now,
	new CancellationChangeToken(cancellationTokenSource.Token));

_cache.Set(
	ChildsCacheKey,
	DateTime.Now,
	new CancellationChangeToken(cancellationTokenSource.Token));

ASP.NET Core - 缓存之内存缓存(下)

2.7 一些注意事项

  • 使用回调重新填充缓存项时:

    • 多个请求可以发现缓存的键值为空,因为回调没有完成。
    • 这可能会导致多个线程重新填充缓存项。

  • 当使用一个缓存条目创建另一个缓存条目时,子条目会复制父条目的到期令牌和基于时间的到期设置。 手动删除或更新父条目时,子条目不会过期。

官方文档上还有另外几条,但是我这边在上面有讲过了,这里就不再重复了。



参考文章:
ASP.NET Core 中的内存中缓存



ASP.NET Core 系列:

目录:ASP.NET Core 系列总结
上一篇:ASP.NET Core - 缓存之内存缓存(上)
下一篇:ASP.NET Core - 缓存之分布式缓存文章来源地址https://www.toymoban.com/news/detail-410594.html

到了这里,关于ASP.NET Core - 缓存之内存缓存(下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ASP.NET Core教程:ASP.NET Core 程序部署到Windows系统

    本篇文章介绍如何将一个ASP.NET Core Web程序部署到Windows系统上。这里以ASP.NET Core WebApi为例进行讲解。首先创建一个ASP.NET Core WebApi项目,使用默认的Values控制器,这里使用Visual Studio 2019创建一个ASP.NET Core 3.1d的WebApi项目。 创建新项目的时候选项ASP.NET Core Web应用程序,如下图所

    2023年04月08日
    浏览(56)
  • ASP.NET Core MVC -- 将视图添加到 ASP.NET Core MVC 应用

    右键单击“视图”文件夹,然后单击“添加”“新文件夹”,并将文件夹命名为“HelloWorld”。 右键单击“Views/HelloWorld”文件夹,然后单击“添加”“新项”。 在“添加新项 - MvcMovie”对话框中: 在右上角的搜索框中,输入“视图” 选择“Razor 视图 - 空” 保持“名称”框的

    2024年02月13日
    浏览(91)
  • ASP.NET和ASP.NET Core的区别

    ASP.NET和ASP.NET Core是两个不同的Web应用程序框架,它们都是由Microsoft开发的。ASP.NET是Microsoft推出的第一个Web应用程序框架,而ASP.NET Core是其最新版本。本文将介绍ASP.NET和ASP.NET Core的简介和区别。 ASP.NET的简介 ASP.NET是一个基于.NET框架的Web应用程序框架,它是Microsoft推出的第一

    2024年02月16日
    浏览(76)
  • Asp.Net VS ASP.NET Core 请求管道

    参考链接 ASP.NET CORE 启动过程及源码解读 请求进入Asp.Net工作进程后,由进程创建HttpWorkRequest对象,封装此次请求有关的所有信息,然后进入HttpRuntime类进行进一步处理。HttpRuntime通过请求信息创建HttpContext上下文对象,此对象将贯穿整个管道,直到响应结束。同时创建或从应用

    2024年02月04日
    浏览(81)
  • 【ASP.NET Core 基础知识】--最佳实践和进阶主题--设计模式在ASP.NET Core中的应用

    一、设计模式概述 1.1 什么是设计模式 设计模式是在软件设计过程中反复出现的、经过验证的、可重用的解决问题的方法。它们是针对特定问题的通用解决方案,提供了一种在软件开发中可靠的指导和标准化方法。设计模式通常描述了一种在特定情景下的解决方案,包括了问

    2024年02月21日
    浏览(160)
  • ASP.NET Core SingleR Core:WebApi + .net 客户端开发

    我之前稍微研究了一下SignalR Core。用起来还行。简单来说SignalR就是用来解决实时通讯的问题的。 ASP.NET Core SingleR:初次体验和简单项目搭建 SignalR支持三种客户端,C#,Java,JavaScirpt。基本够用了。本身就是微软开发的,肯定支持自己的语言。因为是Websocket的上层封装,所以也要支

    2024年01月20日
    浏览(134)
  • ASP.NET Core —配置系统

    一个应用要运行起来,往往需要读取很多的预设好的配置信息,根据约定好的信息或方式执行一定的行为。 配置的本质就是软件运行的参数,在一个软件实现中需要的参数非常多,如果我们以 Hard Code (硬编码)的方式写在应用代码中,这样配置就会很乱,而且后续也不容易修

    2024年02月08日
    浏览(53)
  • ASP.NET Core 8 基础

    2023年11月将发布发布.NET 8,基于.NET 8 的 ASP.NET Core 8.0也会一并发布,这是继ASP.NET Core 6.0之后,又一个重要版本,因为引入了nativeAOT,在性能上有很大提升,所以系统地学习一下这项技术。 ASP.NET Core 的几个主要优势: 跨平台,支持 Windows, macOS, Linux,Docker,Azure和AWS等云服务自

    2024年02月11日
    浏览(49)
  • Asp.Net Core 6 - 概述

    Q: 什么是 .NET? A:.NET 是一个开发人员平台,由工具、编程语言、库组成,用于构建许多不同类型的应用程序。使用 .NET,可以使用多种语言、编辑器和库来构建 Web、移动、桌面、游戏和 IoT 等,可以使用 C#、F# 或 Visual Basic 编写 .NET 应用。 .NET 发展至今,出现了两种实现 n

    2024年02月06日
    浏览(54)
  • ASP.NET Core IOC容器

      ServiceCollection 抽象和具体之间多种注册方式

    2024年02月09日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包