Dot-Net
.Net Core MemoryCache PostEvictionCallback 無法正常工作
我在 Microsoft.Extensions.Caching.Memory.MemoryCache 中設置了具有滑動到期的記憶體項。我想在每次記憶體項過期時觸發回調,但直到我查詢記憶體中過期的記憶體項時才會觸發回調。
這是程式碼:
using System; using Microsoft.Extensions.Caching.Memory; namespace Memcache { public class Program { private static MemoryCache _cache; private static int _cacheExpSecs; public static void Main(string[] args) { _cache = new MemoryCache(new MemoryCacheOptions()); _cacheExpSecs = 2; var cacheEntryOptions = new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(_cacheExpSecs)) .RegisterPostEvictionCallback(callback: EvictionCallback); _cache.Set(1, "One", cacheEntryOptions); _cache.Set(2, "Two", cacheEntryOptions); var autoEvent = new System.Threading.AutoResetEvent(false); System.Threading.Timer timer = new System.Threading.Timer(checkCache, autoEvent, 1000, 6000); Console.Read(); } private static void checkCache(Object o) { if(_cache.Get(1)!=null) { Console.WriteLine(string.Format(@"checkCache: Cache with key {0} will be removed manually and will trigger the callback.", 1)); _cache.Remove(1); } else { Console.WriteLine(string.Format("checkCache: Cache with key {0} is expired.", 1)); } if(_cache.Get(2) != null) { Console.WriteLine(string.Format("checkCache: Cache with key {0} will expire in {1} seconds, but won't trigger the callback until we check it's value again.", 2, _cacheExpSecs)); } else { Console.WriteLine(string.Format("checkCache: Cache with key {0} is expired.", 2)); } } private static void EvictionCallback(object key, object value, EvictionReason reason, object state) { Console.WriteLine(); Console.WriteLine("/*****************************************************/"); Console.WriteLine(string.Format("/* EvictionCallback: Cache with key {0} has expired. */", key)); Console.WriteLine("/*****************************************************/"); Console.WriteLine(); } } }
發生這種情況是因為在您查詢該項目並檢查到期之前,該項目不會被驅逐
(來自 來源
MemoryCacheStore.Get(MemoryCacheKey key))internal MemoryCacheEntry Get(MemoryCacheKey key) { MemoryCacheEntry entry = _entries[key] as MemoryCacheEntry; // has it expired? if (entry != null && entry.UtcAbsExp <= DateTime.UtcNow) { Remove(key, entry, CacheEntryRemovedReason.Expired); entry = null; } // update outside of lock UpdateExpAndUsage(entry); return entry; }或者
Trim()由於記憶體壓力而在內部呼叫時(來自 來源
TrimInternal(int percent))/*SNIP*/ trimmedOrExpired = _expires.FlushExpiredItems(true); if (trimmedOrExpired < toTrim) { trimmed = _usage.FlushUnderUsedItems(toTrim - trimmedOrExpired); trimmedOrExpired += trimmed; } /*SNIP*/如果您的系統目前記憶體不足,無法觸發修剪,那麼項目將被驅逐的唯一時間是在嘗試檢索它們時。
要添加到接受答案和評論,您可以使用過期取消令牌強制記憶體過期並自動驅逐。
int expirationMinutes = 60; var expirationTime = DateTime.Now.Add(expirationMinutes); var expirationToken = new CancellationChangeToken( new CancellationTokenSource(TimeSpan.FromMinutes(expirationMinutes + .01)).Token); var cacheEntryOptions = new MemoryCacheEntryOptions() // Pin to cache. .SetPriority(CacheItemPriority.NeverRemove) // Set the actual expiration time .SetAbsoluteExpiration(expirationTime) // Force eviction to run .AddExpirationToken(expirationToken) // Add eviction callback .RegisterPostEvictionCallback(callback: CacheItemRemoved, state: this);`
缺乏內置的計時器行為,舊的曾經有的,應該是設計使然,這是推薦的。見:https ://github.com/aspnet/Caching/issues/248