當前位置: 妍妍網 > 碼農

.NET 9 Preview 1 中 MemoryCache 的更新

2024-02-24碼農

.NET 9 Preview 1 中 MemoryCache 的更新

Intro

.NET 9 Preview 1 中為 MemoryCache 添加了一個 Keys 內容,我們可以透過它來獲取 memory cache 中的緩存的 key list 了,另外新增了一個帶 MemoryCacheEntryOptions 參數的 GetOrCreate(Async) 多載方法

Sample

Keys Sample

新增的 API:

public classMemoryCache
{
public System.Collections.Generic.IEnumerable<object> Keys { get; }
}

來看下使用範例:

Console.WriteLine("MemoryCache keys non-di sample");
var memoryCache = new MemoryCache(new MemoryCacheOptions());
memoryCache.Set("user:1:roles""user,manager");
memoryCache.Set("user:1:permission""read,write");
memoryCache.Set("user:2:roles""user");
memoryCache.Set("user:2:permission""read");
foreach (var cacheKey in memoryCache.Keys)
{
Console.WriteLine(cacheKey.ToString());
if (cacheKey isstring cacheKeyStr && cacheKeyStr.StartsWith("user:2:"))
{
memoryCache.Remove(cacheKey);
}
}
Console.WriteLine("some keys had been removed");
foreach (var cacheKey in ((MemoryCache)memoryCache).Keys)
{
Console.WriteLine(cacheKey.ToString());
}

這個範例是直接 new 不使用依賴註入的方式,這裏模擬了清除使用者緩存的一個操作,將使用者 2 的緩存刪除並打印所有的 cache key

輸出結果如下:

keys-non-di-sample-output

再來看一下使用依賴註入的範例,大體上差不多,只是我們需要轉換一下型別,因為這個 Keys 是定義在 MemoryCache 型別上, IMemoryCache 介面並未定義

Console.WriteLine("MemoryCache keys dependency injection sample");
usingvar services = new ServiceCollection()
.AddMemoryCache()
.BuildServiceProvider();
var memoryCache = services.GetRequiredService<IMemoryCache>();
memoryCache.Set("user:1:roles""user,manager");
memoryCache.Set("user:1:permission""read,write");
memoryCache.Set("user:2:roles""user");
memoryCache.Set("user:2:permission""read");
foreach (var cacheKey in ((MemoryCache)memoryCache).Keys)
{
Console.WriteLine(cacheKey.ToString());
if (cacheKey isstring cacheKeyStr && cacheKeyStr.StartsWith("user:2:"))
{
memoryCache.Remove(cacheKey);
}
}
Console.WriteLine("some keys had been removed");
foreach (var cacheKey in ((MemoryCache)memoryCache).Keys)
{
Console.WriteLine(cacheKey.ToString());
}

輸出結果如下:

keys-di-sample-output

GetOrCreate(Async) override

新的 API 定義如下:

 namespace Microsoft.Extensions.Caching.Memory {
public static class CacheExtensions {
+ public static TItem? GetOrCreate<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, TItem> factory, MemoryCacheEntryOptions? createOptions);
+ public static Task<TItem?> GetOrCreateAsync<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, Task<TItem>> factory, MemoryCacheEntryOptions? createOptions);
}
 }

在原來的 GetOrCreate / GetOrCreateAsync 方法的基礎上增加了 MemoryCacheEntryOptions 參數,這樣我們可以在 options 參數設定緩存的過期時間等,我們 factory 方法就能比較簡單了

使用範例如下:

Console.WriteLine("MemoryCache keys dependency injection sample");
usingvar services = new ServiceCollection()
.AddMemoryCache()
.BuildServiceProvider();
var memoryCache = services.GetRequiredService<IMemoryCache>();
var key = "user:2:roles";
FetchValue();
Thread.Sleep(1000);
FetchValue();
Thread.Sleep(3000);
FetchValue();
voidFetchValue()
{
memoryCache.GetOrCreate("no-expiration", _ =>
{
Console.WriteLine("fetch value from source for no-expiration key");
return"user";
});
memoryCache.GetOrCreate(key, _ =>
{
Console.WriteLine("fetch value from source");
return"user";
},
new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3) });
}

這裏有兩個緩存,用於對比設定和不設定的區別, no-expiration 沒有設定過期時間,另外一個設定了三秒的過期時間,輸出結果如下:

可以看到 fetch value from source 出現了兩次,第一次呼叫的時候緩存不存所以從 source 去取走了 factory 的邏輯,最後一次緩存過期了所以再次從 source 拿了一次,而 no-expiration key 因為沒有過期時間,所以只有在第一次取得時候從 source 取,後面都是從緩存獲取

這個 API 的實作比較簡單,蹭了一個 PR,哈哈

References

  • https://github.com/dotnet/runtime/issues/36554

  • https://github.com/dotnet/runtime/pull/94992/files

  • https://github.com/dotnet/runtime/issues/92101

  • https://github.com/dotnet/runtime/pull/94335