如何清除MemoryCache?

Ret*_*der 91 c# memory caching .net-4.0 memorycache

我使用MemoryCache类创建了一个缓存.我添加了一些项目,但是当我需要重新加载缓存时,我想首先清除它.最快的方法是什么?我应该遍历所有项目并一次删除一个项目还是有更好的方法?

GvS*_*GvS 57

Dispose 现有的MemoryCache并创建一个新的MemoryCache对象.

  • @LaustN你能详细说明MemoryCache.Default造成的"悲伤"吗?我目前正在使用MemoryCache.Default ... MSDN的MemoryCache文档让我想知道是否建议处理和重新创建:"除非需要,否则不要创建MemoryCache实例.如果在客户端和Web应用程序中创建缓存实例,则MemoryCache实例应该在应用程序生命周期的早期创建." 这适用于.Default吗?我不是说使用Dispose是错误的,我老实说只是在寻找对这一切的澄清. (10认同)
  • @ElonU:以下Stack Overflow答案解释了处理默认实例时可能遇到的一些问题:http://stackoverflow.com/a/8043556/216440.引用:"缓存的状态设置为指示缓存已被释放.任何尝试调用更改缓存状态的公共缓存方法(例如添加,删除或检索缓存条目的方法)都可能导致意外例如,如果在释放缓存后调用Set方法,则会发生无操作错误." (8认同)
  • 认为值得一提的是`Dispose` _does_调用附加到当前缓存项的任何`CacheEntryRemovedCallback`. (6认同)
  • 我最初使用MemoryCache.Default,导致Dispose给我一些悲伤.尽管如此,Dispose最终成为我能找到的最佳解决方案.谢谢. (2认同)

Tho*_*ham 54

枚举的问题

所述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
Run Code Online (Sandbox Code Playgroud)

由于实现将缓存分割为多个Dictionary对象,因此它必须将所有内容组合到一个集合中以便返回枚举器.每次调用GetEnumerator都会执行上面详述的完整复制过程.新创建的Dictionary包含对原始内部键和值对象的引用,因此不会复制实际的缓存数据值.

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

更好,更灵活的解决方案

这是一种清除缓存的有效方法,只需在现有的变更监控基础架构上构建.它还提供了清除整个缓存或仅清除命名子集的灵活性,并且没有上面讨论的问题.

// 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @AaronM这个解决方案还不仅仅是处理缓存并实例化一个新缓存吗? (9认同)
  • 似乎是缺少Region功能的实现. (8认同)
  • 我不推荐这种模式用于一般用途.它的速度慢,没有执行的错误,但处理方法非常慢.2.如果您的缓存中的项目已过期,则仍会调用更改监视器.3.我的机器正在吞下所有的CPU,并且在运行性能测试时花了很长时间从缓存中清除30k项目.等了5多分钟后,我刚刚杀了几次测试. (7认同)

mag*_*tte 33

来自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);
}
Run Code Online (Sandbox Code Playgroud)

  • 从[documentation](http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.getenumerator.aspx)中:_Retrieving MemoryCache实例的枚举器是一项资源密集型和阻塞操作.因此,不应将枚举器用于生产应用程序._ (32认同)
  • @JacobMorrison可以说,单元测试不是"生产应用程序":) (4认同)
  • @emberdude它与检索枚举器完全一样 - 你对Select()`的实现有什么作用? (3认同)
  • 就个人而言,我在我的单元测试 [TestInitialize] 函数中使用它来清除每个单元测试的内存缓存。否则,在尝试比较 2 个函数之间的性能时,缓存会在单元测试中持续存在,给出意想不到的结果。 (2认同)
  • @Mels 可以说,单元测试应该按照与“生产应用程序”相同的标准编写!:) (2认同)

Rog*_*Far 21

var cacheItems = cache.ToList();

foreach (KeyValuePair<String, Object> a in cacheItems)
{
    cache.Remove(a.Key);
}
Run Code Online (Sandbox Code Playgroud)

  • 这跟@Tony的反应风险相同; 请看我的评论. (3认同)
  • @AlexAngas - 他可能已经改名为magritte.另见http://stackoverflow.com/questions/4183270/how-to-clear-the-net-4-memorycache/22388943#22388943 (2认同)

use*_*678 9

如果性能不是问题,那么这个漂亮的单行将会起到作用:

cache.ToList().ForEach(a => cache.Remove(a.Key));
Run Code Online (Sandbox Code Playgroud)


bot*_*ked 7

似乎有一种修剪方法.

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

cache.Trim(100)
Run Code Online (Sandbox Code Playgroud)

编辑: 经过挖掘更多,似乎调查修剪是不值得的时间

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

如何清除System.Runtime.Caching.MemoryCache