MemoryCache 如何清除全部缓存?


最近有个需求需要定时清理服务器上所有的缓存。本来以为很简单的调用一下 MemoryCache.Clear 方法就完事了。谁知道 MemoryCache 类以及 IMemoryCache 扩展方法都没有 Clear 方法。这可给难住了,于是想找到所有的 Keys 来一个个 Remove ,谁知道居然也没有获取所有 Key 的方法。于是研究了一下 ,找到一些方法,下面介绍两个方法:

自定义 CacheWrapper 包装类

MemoryCache 构造 Entry 的时候支持传入 CancellationChangeToken 对象,当 CancellationChangeToken.Cancel 触发的时候会自动使该对象过期。那么我们只要对 MemoryCache 类包装一下很容易实现一个自己的 Cache 类。

 public class CacheWrapper
    {
        private readonly IMemoryCache _memoryCache;
        private CancellationTokenSource _resetCacheToken = new();

        public CacheWrapper(IMemoryCache memoryCache)
        {
            _memoryCache = memoryCache;
        }

        public void Add(object key, object value, MemoryCacheEntryOptions memoryCacheEntryOptions)
        {
            using var entry = _memoryCache.CreateEntry(key);
            entry.SetOptions(memoryCacheEntryOptions);
            entry.Value = value;

            // add an expiration token that allows us to clear the entire cache with a single method call
            entry.AddExpirationToken(new CancellationChangeToken(_resetCacheToken.Token));
        }

        public object Get(object key)
        {
            return _memoryCache.Get(key);
        }

        public void Remove(object key)
        {
            _memoryCache.Remove(key);
        }

        public void Clear()
        {
            _resetCacheToken.Cancel(); // this triggers the CancellationChangeToken to expire every item from cache

            _resetCacheToken.Dispose(); // dispose the current cancellation token source and create a new one
            _resetCacheToken = new CancellationTokenSource();
        }
    }

然后单元测试测试一下:


        [TestMethod()]
        public void ClearTest()
        {
            var memCache = new MemoryCache(new MemoryCacheOptions());
            var wrapper = new CacheWrapper(memCache);

            for (int i = 0; i < 10; i++)
            {
                wrapper.Add(i.ToString(), new object(), new MemoryCacheEntryOptions());
            }

            Assert.IsNotNull(wrapper.Get("1"));
            Assert.IsNotNull(wrapper.Get("9"));

            wrapper.Clear();

            for (int i = 0; i < 10; i++)
            {
                Assert.IsNull(wrapper.Get(i.ToString()));
            }

            for (int i = 0; i < 10; i++)
            {
                wrapper.Add(i.ToString(), new object(), new MemoryCacheEntryOptions());
            }

            Assert.IsNotNull(wrapper.Get("1"));
            Assert.IsNotNull(wrapper.Get("9"));

            wrapper.Clear();

            for (int i = 0; i < 10; i++)
            {
                Assert.IsNull(wrapper.Get(i.ToString()));
            }

        }

测试通过。

Compact 方法

以上 CacheWrapper 类虽然可以实现我们想要的功能,但是对于原来的程序有侵入,需要使用 CacheWrapper 类替换默认的 MemoryCache 类,不是太好。于是不死心继续研究,后来直接看了 MemoryCache 的代码(源码在这),开源真香。发现 MemoryCache 有个 Compact 方法好像在干删除的勾当。也怪我英文不好,这单词是压缩的意思,居然才发现。。。。于是我们的清除所有对象的需求不就轻而易举了么?

 /// Remove at least the given percentage (0.10 for 10%) of the total entries (or estimated memory?), according to the following policy:
        /// 1. Remove all expired items.
        /// 2. Bucket by CacheItemPriority.
        /// 3. Least recently used objects.
        /// ?. Items with the soonest absolute expiration.
        /// ?. Items with the soonest sliding expiration.
        /// ?. Larger objects - estimated by object graph size, inaccurate.
MemoryCache.Compact(double percentage);

Compact 方法会对缓存的对象进行压缩,参数是个double,0.1 表示压缩 10% ,那么传 1.0 就是压缩 100%,那不就是 Clear All 么。所以我可以使用 Compact(1.0) 来清除所有的缓存对象。单元测试跑一下:

[TestMethod()]
        public void CompactTest()
        {
            var memCache = new MemoryCache(new MemoryCacheOptions());

            for (int i = 0; i < 10; i++)
            {
                memCache.Set(i.ToString(), new object(), new MemoryCacheEntryOptions());
            }

            Assert.IsNotNull(memCache.Get("1"));
            Assert.IsNotNull(memCache.Get("9"));

            memCache.Compact(1);

            for (int i = 0; i < 10; i++)
            {
                Assert.IsNull(memCache.Get(i.ToString()));
            }

            for (int i = 0; i < 10; i++)
            {
                memCache.Set(i.ToString(), new object(), new MemoryCacheEntryOptions());
            }

            Assert.IsNotNull(memCache.Get("1"));
            Assert.IsNotNull(memCache.Get("9"));

            memCache.Compact(1);

            for (int i = 0; i < 10; i++)
            {
                Assert.IsNull(memCache.Get(i.ToString()));
            }
        }

完美通过。
这里简单介绍下 Compact 方法。根据注释它会按照已下优先级删除对象:

  1. 过期的对象
  2. CacheItemPriority 设置的优先级,等级越高越不容易被删除
  3. 最近最少被使用的对象
  4. 绝对过期时间
  5. 滑动过期时间
  6. 大对象

PS

  1. 评论区有人提到 main 分支的代码上微软已经加上了 Clear 方法。https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs#L272 感谢 @yi念之间 兄弟指出。
  2. Compact 方法有个问题,如果 CacheItemPriority 设置为 NeverRemove 那么就删不掉了。感谢 @有态度的马甲 兄弟指出。
  3. 这里说的是 Microsoft.Extensions.Caching 命名空间下的 MemoryCache , 不是 System.Runtime下的那个 。

关注我的公众号一起玩转技术

文章来源:https://www.cnblogs.com/kklldog/p/how-clear-all-memory-cache.html

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
管理员
上一篇:WPF开发随笔收录-自定义图标控件
下一篇:iNeuOS工业互联网操作系统,发布3.6.4版本:云端安全控制和实时日志功能,附Chrome、Firefox和Edge浏览器测试性能对比
评论列表

发表评论

评论内容
昵称:
验证码:
验证码
关联文章

MemoryCache 如何清除全部缓存
.NET Core 缓存使用之 MemoryCache
.NET Core ResponseCache 浏览器缓存
GIT Bash 简单讲解-git如何推/拉代码
JS清除Input File 的选择文件 javascript清除Input File选择文件
使用.NET 6开发TodoList应用(22)——实现缓存
页面没有缓存,Keep-alive失效
selenium爬虫被检测到 该如何
解决VUE发布后因为浏览器缓存造成页面没更新的问题
asp.net mvc Action直接返回图片不被浏览器缓存
uniapp vue3 下 pinia 的本地数据缓存插件
如何将命令添加到VisualStudio控制台?
如何提升.NET控制台应用体验?
git删除全部提交历史,成为一个新的仓库
.net core如何添加一个唯一的请求ID
.NET下如何拦截鼠标、键盘消息?Win32NET来帮你
WPF DataGrid 如何将被选中行带到视野中
如何更改winform中Groupbox的Controls属性内控件的排序
在 SA 和 Windows 等账户都被禁用的情况下如何登录?
如何在进销存系统中进行账期管理和封账操作

热门标签
.NET Core .NET Reactor ag-grid AI发布 api安全 ASP.NET Core C#DLL加密 C#播放声音 C#代码混淆 C#代码加密 ChromeDriver Codex DateTime DBeaver devexpress devTool DLL混淆 edge.js EF EFCore Electron element-ui el-form el-table excel FastReport FileStream FolderBrowerDialog FolderSelectDialog form提交 git gridcontrol gridview input javascript json字符串 JS转换对象JSON jwt JWT授权 linq log Math MCP mitmproxy MVC MySQL Navicat netstat nginx node_modules NSwag Nuget Nuget镜像 number PowerShell pyinstaller python pythoncom python爬虫 python抓包 pywin32 redis Requests-html RestSharp Selenium sql SQL Server Swagger to-cms Visual Studio VSCode vue VueRouter vue路由 VUE页面通讯 Webpack Windows Windows服务 winform wmi xlrd yaml YESCMS YESWEB开发框架 白象 表单提交 播放声音 打开URL 代码混淆 弹窗提醒 端口占用 对象转换 分布式 公共字典 机器码 进程排查 静态资源 开发指南 路由参数 密钥 配置教程 配置文件 权限 人工智能 任务 任务调度 日期间隔 日志 日志记录 省市区 授权验证 数据库 四舍五入 文案 文件读取 文件夹选择 文件目录选择 问题排查 行政区域数据 页面通讯 中间件 CSharp 事务锁 工单系统 并发控制 重复提交 CMS Markdig Markdown markdown-it marked 技术选型 VS Code 开发工具 源代码管理 版本控制 Docker PostgreSQL 时区 部署排查 CMS架构 EF Core 主题系统 二次开发 插件系统 容器 运维命令 镜像清理 Linux NAS 远程挂载 飞牛 fnOS S/4HANA SAP GUI SAP HANA SAP R/3 SAP入门 SAP版本 ERP SAP SAP MM 库存管理 物料管理 采购管理 入门教程 SAP S/4HANA SPRO 企业结构 采购组织 MM01 物料主数据 物料类型 BP分组 业务伙伴 供应商主数据 ME41 RFQ 库存物料 采购流程 ME51 消耗性物料 科目分配 采购申请 AC03 ML81N 外部服务 服务主数据 Business Partner SAP培训 ME51N MM模块 Lean Services MM-SRV 外部服务采购 PIR 供应来源 采购主数据 采购信息记录 ME31K 框架协议 计划协议 采购合同 ME01 供应来源确定 货源清单 MEQ1 供应源确定 配额安排 配额评分 MD04 MD21 MRP 计划文件 需求计划 批量程序 MD01N MD02 MRP Live MD05 MM 物料计划 优化采购 供应源 采购订单
联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码