C# MemoryCache避免在关机时刷新
我在web服务集成层中使用C# MemoryCache避免在关机时刷新,c#,code-cleanup,application-shutdown,C#,Code Cleanup,Application Shutdown,我在web服务集成层中使用System.Runtime.MemoryCache来保存一些外部的、检索速度较慢的产品列表。但是,我想在它们过期时刷新它们,让我的呼叫者不再等待它。因此,我正在使用IIS7.5预热此缓存,并使用RemovedCallback在过期时重新加载数据 但是,当web池进程正常终止时会发生什么?MemoryCache是一次性的,因此它会将我的对象踢出,在这一点上,我将尝试重新填充一个新实例,同时暂停整个过程。我有没有办法安全地检测到我不应该重新加载数据 internal cl
System.Runtime.MemoryCache
来保存一些外部的、检索速度较慢的产品列表。但是,我想在它们过期时刷新它们,让我的呼叫者不再等待它。因此,我正在使用IIS7.5预热此缓存,并使用RemovedCallback
在过期时重新加载数据
但是,当web池进程正常终止时会发生什么?MemoryCache是一次性的,因此它会将我的对象踢出,在这一点上,我将尝试重新填充一个新实例,同时暂停整个过程。我有没有办法安全地检测到我不应该重新加载数据
internal class ProductCache {
private static object _lock = new object();
private static string _cid = Guid.NewGuid().ToString();
public static Product[] data
{
get
{
lock (_lock)
{
if (!MemoryCache.Default.Contains(_cid))
{
Product[] p;
try
{
// load data into p
}
catch (System.Exception e)
{
Helper.SafeSendExceptionEmail("Integrator.Caching", e);
throw e;
}
MemoryCache.Default.Add(_cid, p, new CacheItemPolicy()
{
AbsoluteExpiration = DateTimeOffset.Now.AddHours(8),
RemovedCallback = arg =>
{
// query again to force reload
var d = data;
}
});
}
return (Product[])MemoryCache.Default[_cid];
}
}
}
}
好的,通过深入查看
MemoryCache
和MemoryCacheStore
源代码,缓存似乎在域卸载时自动释放,此时它会释放其所有存储,这反过来会删除缓存项,原因是cacheSpecificExecution
。这个原因没有在其他地方使用,所以它必须代表“我要死了”的原因(不过在文档中可能会更清楚)
RemovedCallback
获取具有RemovedReason
的CacheEntryRemovedArguments
实例。我假设(但尚未验证)这只是RemovedReason.Expired
当条目实际过期时。如果内存受到限制等,它也可以被逐出。我在列表中没有看到“我正在关机,所以我将你踢出”的原因。有一个模糊的原因(cacheSpecificExecution=4,//某个缓存项被逐出的原因是由特定缓存定义的),但这似乎太模糊了……但您只想在该项过期时重新加载,对吗?您不需要知道缓存是否正在关闭,只要您的条目因过期而被删除即可。如果由于任何其他原因删除了它,您都不想重新加载它(想象一下,如果缓存由于内存压力而试图删除条目,而您又将它们扔回缓存,那么会出现混乱!)最坏的情况实际上是严重的——不仅内存不足,而且应用程序还消耗了100%的CPU,除了循环项目外,什么都不做。如果让数据驻留在内存中非常关键,那么您可能首先不需要一个尽力而为的缓存——编写自己的类来保持信息驻留,然后定期重新加载它。这样你就不会试图把一个方形的钉子塞进一个圆形的洞里。我想说的是:缓存应该会加快速度,但如果它被完全移除,则不会影响功能的正确性。因此,只有在已知条目已过期时才重新插入条目,而不是出于任何其他删除原因(如有人显式调用Remove
)的保守实现应该是完全合法的。如果您正在“挖掘源代码”以获得确切的实现细节,那么您已经非常依赖于特定的行为,而不是任何理智的理由。因此,我建议编写一个完全满足您需要的类。
public void Dispose()
{
if (Interlocked.Exchange(ref this._disposed, 1) == 0)
{
this._expires.EnableExpirationTimer(false);
ArrayList list = new ArrayList(this._entries.Count);
lock (this._entriesLock)
{
foreach (DictionaryEntry entry in this._entries)
{
MemoryCacheEntry entry2 = entry.Value as MemoryCacheEntry;
list.Add(entry2);
}
foreach (MemoryCacheEntry entry3 in list)
{
MemoryCacheKey key = entry3;
entry3.State = EntryState.RemovingFromCache;
this._entries.Remove(key);
}
}
foreach (MemoryCacheEntry entry4 in list)
{
this.RemoveFromCache(entry4, CacheEntryRemovedReason.CacheSpecificEviction, false);
}
this._insertBlock.Close();
}
}