您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

C# MemoryCache 如何清除全部缓存

时间:2021-12-30 11:28:50  来源:博客园  作者:开发软件

最近有个需求需要定时清理服务器上所有的缓存。本来以为很简单的调用一下 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



Tags:C#   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
最近有个需求需要定时清理服务器上所有的缓存。本来以为很简单的调用一下 MemoryCache.Clear 方法就完事了。谁知道 MemoryCache 类以及 IMemoryCache 扩展方法都没有 Clear...【详细内容】
2021-12-30  Tags: C#  点击:(0)  评论:(0)  加入收藏
一、简介很多时候我们都需要用到一些验证的方法,有时候需要用正则表达式校验数据时,往往需要到网上找很久,结果找到的还不是很符合自己想要的。所以我把自己整理的校验帮助类分...【详细内容】
2021-12-27  Tags: C#  点击:(4)  评论:(0)  加入收藏
读取SQLite数据库,就是读取一个路径\\192.168.100.**\position\db.sqlite下的文件<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/...【详细内容】
2021-12-16  Tags: C#  点击:(24)  评论:(0)  加入收藏
一文看懂"async"和“await”关键词是如何简化了C#中多线程的开发过程当我们使用需要长时间运行的方法(即,用于读取大文件或从网络下载大量资源)时,在同步的应用程序中,应用程序本...【详细内容】
2021-12-01  Tags: C#  点击:(24)  评论:(0)  加入收藏
OpenCV(Open Source Computer Vision Library)是一个(开源免费)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android、ios等操作系统上,它轻量级而且高效---由一系列...【详细内容】
2021-11-11  Tags: C#  点击:(52)  评论:(0)  加入收藏
在进行C#接口开发时经常需要将数据集转换成json返回,下面介绍一种将DataTable数据转换成实体类,然后再转换成json的方法。一、创建全病案类/// <summary> /// 全病案 //...【详细内容】
2021-11-04  Tags: C#  点击:(45)  评论:(0)  加入收藏
C# 获取网络路径文件大小信息的方法private void button1_Click(object sender, EventArgs e){label2.Text= GetInfo(textBox1.Text);}private string GetInfo(string URL){...【详细内容】
2021-10-29  Tags: C#  点击:(54)  评论:(0)  加入收藏
现如今二维码广泛应用,已经成为了生活中不可或缺的东西;所以我们日常的开发中,也少不了对二维码的生成或者解析。此文讲述一下使用C# 生成和解析二维码 实现功能:将字符串生成二...【详细内容】
2021-10-21  Tags: C#  点击:(62)  评论:(0)  加入收藏
最开始接触.net大概是2003年,当时用的还是framework1.1,那是CAM项目,使用.net主要是利用RemotingService做分布式开发,我当时做其中的一个子系统,因为之前一直都是C++开发,对C#一...【详细内容】
2021-08-17  Tags: C#  点击:(106)  评论:(0)  加入收藏
最近想自己做个录屏工具玩玩,使用的是ffmpeg,录屏是没有问题,在取麦克风及电脑声卡遇到了难题,ffmpeg也可以获取到设备名称但是没办法解析 ( 指令:ffmpeg -list_devices true -f d...【详细内容】
2021-08-04  Tags: C#  点击:(281)  评论:(0)  加入收藏
▌简易百科推荐
最近有个需求需要定时清理服务器上所有的缓存。本来以为很简单的调用一下 MemoryCache.Clear 方法就完事了。谁知道 MemoryCache 类以及 IMemoryCache 扩展方法都没有 Clear...【详细内容】
2021-12-30  开发软件  博客园  Tags:C#   点击:(0)  评论:(0)  加入收藏
一、简介很多时候我们都需要用到一些验证的方法,有时候需要用正则表达式校验数据时,往往需要到网上找很久,结果找到的还不是很符合自己想要的。所以我把自己整理的校验帮助类分...【详细内容】
2021-12-27  中年农码工    Tags:C#   点击:(4)  评论:(0)  加入收藏
引言在学习C语言或者其他编程语言的时候,我们编写的一个程序代码,基本都是在屏幕上打印出 hello world ,开始步入编程世(深)界(坑)的。C 语言版本的 hello world 代码:#include <std...【详细内容】
2021-12-21  一起学嵌入式    Tags:C 语言   点击:(12)  评论:(0)  加入收藏
读取SQLite数据库,就是读取一个路径\\192.168.100.**\position\db.sqlite下的文件<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/...【详细内容】
2021-12-16  今朝我的奋斗    Tags:c#   点击:(24)  评论:(0)  加入收藏
什么是shellshell是c语言编写的程序,它在用户和操作系统之间架起了一座桥梁,用户可以通过这个桥梁访问操作系统内核服务。 它既是一种命令语言,同时也是一种程序设计语言,你可以...【详细内容】
2021-12-16  梦回故里归来    Tags:shell脚本   点击:(18)  评论:(0)  加入收藏
一、编程语言1.根据熟悉的语言,谈谈两种语言的区别?主要浅谈下C/C++和PHP语言的区别:1)PHP弱类型语言,一种脚本语言,对数据的类型不要求过多,较多的应用于Web应用开发,现在好多互...【详细内容】
2021-12-15  linux上的码农    Tags:c/c++   点击:(17)  评论:(0)  加入收藏
1.字符串数组+初始化char s1[]="array"; //字符数组char s2[6]="array"; //数组长度=字符串长度+1,因为字符串末尾会自动添&lsquo;\0&lsquo;printf("%s,%c\n",s1,s2[2]);...【详细内容】
2021-12-08  灯-灯灯    Tags:C语言   点击:(48)  评论:(0)  加入收藏
函数调用约定(Calling Convention),是一个重要的基础概念,用来规定调用者和被调用者是如何传递参数的,既调用者如何将参数按照什么样的规范传递给被调用者。在参数传递中,有两个很...【详细内容】
2021-11-30  小智雅汇    Tags:函数   点击:(22)  评论:(0)  加入收藏
一、问题提出问题:把m个苹果放入n个盘子中,允许有的盘子为空,共有多少种方法?注:5,1,1和1 5 1属同一种方法m,n均小于10二、算法分析设f(m,n) 为m个苹果,n个盘子的放法数目,则先对...【详细内容】
2021-11-17  C语言编程    Tags:C语言   点击:(49)  评论:(0)  加入收藏
一、为什么需要使用内存池在C/C++中我们通常使用malloc,free或new,delete来动态分配内存。一方面,因为这些函数涉及到了系统调用,所以频繁的调用必然会导致程序性能的损耗;另一...【详细内容】
2021-11-17  深度Linux    Tags:C++   点击:(40)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条