最近有個需求需要定時清理服務器上所有的快取,本來以為很簡單的呼叫一下 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 = https://www.cnblogs.com/kklldog/archive/2021/12/21/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 方法,根據注釋它會按照已下優先級洗掉物件:
- 過期的物件
- CacheItemPriority 設定的優先級,等級越高越不容易被洗掉
- 最近最少被使用的物件
- 絕對過期時間
- 滑動過期時間
- 大物件
關注我的公眾號一起玩轉技術

QQ群:1022985150 VX:kklldog 一起探討學習.NET技術
作者:Agile.Zhou(kklldog)
出處:http://www.cnblogs.com/kklldog/
本文著作權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/388880.html
標籤:.NET技术
上一篇:iNeuOS工業互聯網作業系統,發布3.6.4版本:云端安全控制和實時日志功能,附Chrome、Firefox和Edge瀏覽器測驗性能對比
