如何清除MemoryCache?

我已经使用MemoryCache类创build了一个caching。 我添加一些项目,但是当我需要重新加载caching我想先清除它。 什么是最快的方法来做到这一点? 我应该循环所有的项目,并一次删除一个或有更好的办法吗?

Dispose现有的MemoryCache并创build一个新的MemoryCache对象。

枚举的问题

MemoryCache.GetEnumerator()备注部分警告:“检索MemoryCache实例的枚举器是一个资源密集型和阻塞操作,因此枚举器不应在生产应用程序中使用。

这就是为什么 ,用GetEnumerator()实现的伪代码解释的原因

 Create a new Dictionary object (let's call it AllCache) For Each per-processor segment in the cache (one Dictionary object per processor) { Lock the segment/Dictionary (using lock construct) Iterate through the segment/Dictionary and add each name/value pair one-by-one to the AllCache Dictionary (using references to the original MemoryCacheKey and MemoryCacheEntry objects) } Create and return an enumerator on the AllCache Dictionary 

由于实现将caching跨多个Dictionary对象拆分,因此必须将所有内容集中到一个集合中,以便交回枚举器。 每次调用GetEnumerator都会执行上面详述的完整复制过程。 新创build的Dictionary包含对原始内部键和值对象的引用,所以您的实际caching数据值不会重复。

文档中的警告是正确的。 避免使用GetEnumerator() – 包括上面使用LINQ查询的所有答案。

一个更好,更灵活的解决scheme

这是清除caching的一种有效方法,只需构build在现有的变更监视基础结构上即可。 它还提供了清除整个caching或只是一个命名的子集的灵活性,并没有上面讨论的问题。

 // By Thomas F. Abraham (http://www.tfabraham.com) namespace CacheTest { using System; using System.Diagnostics; using System.Globalization; using System.Runtime.Caching; public class SignaledChangeEventArgs : EventArgs { public string Name { get; private set; } public SignaledChangeEventArgs(string name = null) { this.Name = name; } } /// <summary> /// Cache change monitor that allows an app to fire a change notification /// to all associated cache items. /// </summary> public class SignaledChangeMonitor : ChangeMonitor { // Shared across all SignaledChangeMonitors in the AppDomain private static event EventHandler<SignaledChangeEventArgs> Signaled; private string _name; private string _uniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); public override string UniqueId { get { return _uniqueId; } } public SignaledChangeMonitor(string name = null) { _name = name; // Register instance with the shared event SignaledChangeMonitor.Signaled += OnSignalRaised; base.InitializationComplete(); } public static void Signal(string name = null) { if (Signaled != null) { // Raise shared event to notify all subscribers Signaled(null, new SignaledChangeEventArgs(name)); } } protected override void Dispose(bool disposing) { SignaledChangeMonitor.Signaled -= OnSignalRaised; } private void OnSignalRaised(object sender, SignaledChangeEventArgs e) { if (string.IsNullOrWhiteSpace(e.Name) || string.Compare(e.Name, _name, true) == 0) { Debug.WriteLine( _uniqueId + " notifying cache of change.", "SignaledChangeMonitor"); // Cache objects are obligated to remove entry upon change notification. base.OnChanged(null); } } } public static class CacheTester { public static void TestCache() { MemoryCache cache = MemoryCache.Default; // Add data to cache for (int idx = 0; idx < 50; idx++) { cache.Add("Key" + idx.ToString(), "Value" + idx.ToString(), GetPolicy(idx)); } // Flush cached items associated with "NamedData" change monitors SignaledChangeMonitor.Signal("NamedData"); // Flush all cached items SignaledChangeMonitor.Signal(); } private static CacheItemPolicy GetPolicy(int idx) { string name = (idx % 2 == 0) ? null : "NamedData"; CacheItemPolicy cip = new CacheItemPolicy(); cip.AbsoluteExpiration = System.DateTimeOffset.UtcNow.AddHours(1); cip.ChangeMonitors.Add(new SignaledChangeMonitor(name)); return cip; } } } 

http://connect.microsoft.com/VisualStudio/feedback/details/723620/memorycache-class-needs-a-clear-method

解决方法是:

 List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList(); foreach (string cacheKey in cacheKeys) { MemoryCache.Default.Remove(cacheKey); } 
 var cacheItems = cache.ToList(); foreach (KeyValuePair<String, Object> a in cacheItems) { cache.Remove(a.Key); } 

如果性能不是问题,那么这个不错的单线程将会诀窍:

 cache.ToList().ForEach(a => cache.Remove(a.Key)); 

似乎有一个修剪方法。

所以要清除你刚刚做的所有内容

 cache.Trim(100) 

编辑:挖了一些之后,似乎看着修剪是不值得你的时间

https://connect.microsoft.com/VisualStudio/feedback/details/831755/memorycache-trim-method-doesnt-evict-100-of-the-items

如何清除System.Runtime.Caching.MemoryCache

你也可以做这样的事情:

 Dim _Qry = (From n In CacheObject.AsParallel() Select n).ToList() For Each i In _Qry CacheObject.Remove(i.Key) Next 

穿越这个,并在此基础上,写了一个更有效,同时清晰的方法:

  public void ClearAll() { var allKeys = _cache.Select(o => o.Key); Parallel.ForEach(allKeys, key => _cache.Remove(key)); } 

有点改进的马格利特答案。

 var cacheKeys = MemoryCache.Default.Where(kvp.Value is MyType).Select(kvp => kvp.Key).ToList(); foreach (string cacheKey in cacheKeys) { MemoryCache.Default.Remove(cacheKey); }