同事 Roger 碰到一個小雷,跟我說過後,決定記錄一下
因為一些專案的緣故,開發環境是 ASP.NET Core 6 他使用的
Microsoft.Extensions.Caching.Memory.MemoryCache
但是在大量用戶存取(非同步) 的時候造成 Exception
後來其實 Roger 也找到解法了也提供了我我測試一下後就記錄一下
測試,其實你發現在大量非同步執行的時候也就是用戶同步存取的時候會出現錯誤
這也可以很簡單的重現,理論上 GetOrCreate 不應該發生 Create 的動作
var memoryCacher = new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions());
int counter= 0;
//10 Items.
var str = "A,B,C,D,E,F,G,H,I,J";
Parallel.ForEach(str.Split(','), i =>
{
var item = memoryCacher.GetOrCreate("TESTKEY", cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromMinutes(1);
return Interlocked.Increment(ref counter);
});
Console.Write(item +" ");
});
Console.Write("Counter For MemoryCache :" + counter);
//Result:
//2 4 9 5 6 8 1 7 3 7 Counter For MemoryCache :9
之後改用一個套件 LazyCache 來解決這問題
LazyCache.IAppCache cacheService = new LazyCache.CachingService();
int counter2 = 0;
Parallel.ForEach(str.Split(','), i =>
{
var item = cacheService.GetOrAdd("test-key", cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(10);
return Interlocked.Increment(ref counter2);
});
Console.Write(item + " ");
});
Console.Write("Counter For CachingService :" + counter2);
//Result:
//1 1 1 1 1 1 1 1 1 1 Counter For CachingService :1
結果我就寫在註解了
感謝各位開源大大的幫忙
reference:
https://tpodolak.com/blog/2017/12/13/asp-net-core-memorycache-getorcreate-calls-factory-method-multiple-times/
https://learn.microsoft.com/zh-tw/dotnet/api/system.runtime.caching.cacheitempolicy.slidingexpiration?redirectedfrom=MSDN&view=dotnet-plat-ext-7.0
https://learn.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.caching.memory.cacheextensions.getorcreate?view=dotnet-plat-ext-7.0
https://github.com/alastairtree/LazyCache
https://blog.novanet.no/asp-net-core-memory-cache-is-get-or-create-thread-safe/