如何清除system . runtime . cache . memorycache ?

时间:2022-10-27 19:17:38

I use a System.Runtime.Caching.MemoryCache to hold items which never expire. However, at times I need the ability to clear the entire cache. How do I do that?

我使用一个System.Runtime.Caching。MemoryCache保存那些永远不会过期的东西。但是,有时我需要清除整个缓存的能力。我该怎么做呢?

I asked a similar question here concerning whether I could enumerate the cache, but that is a bad idea as it needs to be synchronised during enumeration.

我在这里问了一个类似的问题,关于是否可以枚举缓存,但这不是一个好主意,因为在枚举期间需要同步缓存。

I've tried using .Trim(100) but that doesn't work at all.

我试过使用。trim(100),但这根本不起作用。

I've tried getting a list of all the keys via Linq, but then I'm back where I started because evicting items one-by-one can easily lead to race conditions.

我已经尝试过通过Linq获取所有钥匙的列表,但是现在我又回到了我开始的地方,因为一个接一个地驱逐物品很容易导致比赛状况。

I thought to store all the keys, and then issue a .Remove(key) for each one, but there is an implied race condition there too, so I'd need to lock access to the list of keys, and things get messy again.

我想要存储所有的键,然后为每个键发出. remove (key),但是这里也有一个隐含的race条件,所以我需要锁定对键列表的访问权限,然后事情又变得一团糟。

I then thought that I should be able to call .Dispose() on the entire cache, but I'm not sure if this is the best approach, due to the way it's implemented.

然后我认为我应该能够在整个缓存上调用. dispose(),但是我不确定这是否是最好的方法,因为它的实现方式。

Using ChangeMonitors is not an option for my design, and is unnecassarily complex for such a trivial requirement.

使用changemonitor对我的设计来说不是一种选择,对于这样一个微不足道的需求来说,它是不必要的复杂。

So, how do I completely clear the cache?

那么,如何完全清除缓存呢?

6 个解决方案

#1


13  

You should not call dispose on the Default member of the MemoryCache if you want to be able to use it anymore:

如果您想继续使用MemoryCache的默认成员,则不应该调用dispose:

The state of the cache is set to indicate that the cache is disposed. Any attempt to call public caching methods that change the state of the cache, such as methods that add, remove, or retrieve cache entries, might cause unexpected behavior. For example, if you call the Set method after the cache is disposed, a no-op error occurs. If you attempt to retrieve items from the cache, the Get method will always return Nothing. http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.dispose.aspx

缓存的状态被设置为表明缓存已被处理。任何试图调用改变缓存状态的公共缓存方法,比如添加、删除或检索缓存条目的方法,都可能导致意外行为。例如,如果在缓存被处理后调用Set方法,就会发生无操作错误。如果试图从缓存中检索条目,Get方法将始终不返回任何内容。http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.dispose.aspx

About the Trim, it's supposed to work:

关于修剪,它应该是有用的:

The Trim property first removes entries that have exceeded either an absolute or sliding expiration. Any callbacks that are registered for items that are removed will be passed a removed reason of Expired.

Trim属性首先删除超过绝对或滑动过期的项。为已删除的项注册的任何回调都将被传递为已过期的删除原因。

If removing expired entries is insufficient to reach the specified trim percentage, additional entries will be removed from the cache based on a least-recently used (LRU) algorithm until the requested trim percentage is reached.

如果删除过期的条目不足以达到指定的修剪百分比,那么将根据最近使用的(LRU)算法从缓存中删除额外的条目,直到达到请求的修剪百分比。

But two other users reported it doesnt work on same page so I guess you are stuck with Remove() http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.trim.aspx

但是另外两个用户报告说它不能在同一个页面上工作,所以我猜你被删除了()http://msdn.microsoft.com/en- us/library/system.runtime.memorycache.trim.aspx

Update However I see no mention of it being singleton or otherwise unsafe to have multiple instances so you should be able to overwrite your reference.

但是,我没有看到更新单例或具有多个实例不安全,因此应该能够覆盖引用。

But if you need to free the memory from the Default instance you will have to clear it manually or destroy it permanently via dispose (rendering it unusable).

但是,如果需要从默认实例中释放内存,则必须手动清除内存,或者通过dispose(使其不可用)永久销毁内存。

Based on your question you could make your own singleton-imposing class returning a Memorycache you may internally dispose at will.. Being the nature of a cache :-)

根据您的问题,您可以创建自己的、强制的类,返回一个内存缓存,您可以在内部随意配置它。成为缓存的本质:-)

#2


27  

I was struggling with this at first. MemoryCache.Default.Trim(100) does not work (as discussed). Trim is a best attempt, so if there are 100 items in the cache, and you call Trim(100) it will remove the ones least used.

一开始我还在纠结这个问题。MemoryCache.Default.Trim(100)不工作(如前所述)。Trim是最好的尝试,因此如果缓存中有100个条目,并且您调用Trim(100),它将删除最不常用的条目。

Trim returns the count of items removed, and most people expect that to remove all items.

修剪返回删除项的计数,大多数人期望删除所有项。

This code removes all items from MemoryCache for me in my xUnit tests with MemoryCache.Default. MemoryCache.Default is the default Region.

这段代码为我在使用MemoryCache. default的xUnit测试中从MemoryCache删除所有的项。MemoryCache。默认是默认区域。

foreach (var element in MemoryCache.Default)
{
    MemoryCache.Default.Remove(element.Key);
}

#3


7  

Here's is what I had made for something I was working on...

这是我为我正在做的东西做的东西……

public void Flush()
{
    List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
    foreach (string cacheKey in cacheKeys)
    {
        MemoryCache.Default.Remove(cacheKey);
    }
}

#4


2  

The details in @stefan's answer detail the principle; here's how I'd do it.

@stefan回答中的细节详细说明了原则;我是这么做的。

One should synchronise access to the cache whilst recreating it, to avoid the race condition of client code accessing the cache after it is disposed, but before it is recreated.

在重新创建缓存时,应该同步对缓存的访问,以避免客户端代码在处理缓存之后(但在重新创建缓存之前)访问缓存的竞争条件。

To avoid this synchronisation, do this in your adapter class (which wraps the MemoryCache):

为了避免这种同步,请在您的适配器类(它封装了MemoryCache)中这样做:

public void clearCache() {
  var oldCache = TheCache;
  TheCache = new MemoryCache("NewCacheName", ...);
  oldCache.Dispose();
  GC.Collect();
}

This way, TheCache is always in a non-disposed state, and no synchronisation is needed.

这样,请求始终处于非处理状态,不需要同步。

#5


0  

I ran into this problem too. .Dispose() did something quite different than what I expected.

我也遇到了这个问题。. dispose()做了一些与我预期完全不同的事情。

Instead, I added a static field to my controller class. I did not use the default cache, to get around this behavior, but created a private one (if you want to call it that). So my implementation looked a bit like this:

相反,我向控制器类添加了一个静态字段。我没有使用默认缓存来绕过这种行为,而是创建了一个私有缓存(如果您想这样称呼它的话)。我的实现是这样的

public class MyController : Controller
{

    static MemoryCache s_cache = new MemoryCache("myCache");

    public ActionResult Index()
    {

        if (conditionThatInvalidatesCache)
        {
            s_cache = new MemoryCache("myCache");
        }

        String s = s_cache["key"] as String;

        if (s == null)
        {
            //do work
            //add to s_cache["key"]
        }

        //do whatever next
    }
}

#6


0  

Check out this post, and specifically, the answer that Thomas F. Abraham posted. It has a solution that enables you to clear the entire cache or a named subset.

看看这篇文章,尤其是托马斯·f·亚伯拉罕(Thomas F. Abraham)发布的答案。它有一个解决方案,可以让您清除整个缓存或指定的子集。

The key thing here is:

这里的关键是:

// Cache objects are obligated to remove entry upon change notification.
base.OnChanged(null);

I've implemented this myself, and everything seems to work just fine.

我自己实现了这个,一切似乎都很好。

#1


13  

You should not call dispose on the Default member of the MemoryCache if you want to be able to use it anymore:

如果您想继续使用MemoryCache的默认成员,则不应该调用dispose:

The state of the cache is set to indicate that the cache is disposed. Any attempt to call public caching methods that change the state of the cache, such as methods that add, remove, or retrieve cache entries, might cause unexpected behavior. For example, if you call the Set method after the cache is disposed, a no-op error occurs. If you attempt to retrieve items from the cache, the Get method will always return Nothing. http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.dispose.aspx

缓存的状态被设置为表明缓存已被处理。任何试图调用改变缓存状态的公共缓存方法,比如添加、删除或检索缓存条目的方法,都可能导致意外行为。例如,如果在缓存被处理后调用Set方法,就会发生无操作错误。如果试图从缓存中检索条目,Get方法将始终不返回任何内容。http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.dispose.aspx

About the Trim, it's supposed to work:

关于修剪,它应该是有用的:

The Trim property first removes entries that have exceeded either an absolute or sliding expiration. Any callbacks that are registered for items that are removed will be passed a removed reason of Expired.

Trim属性首先删除超过绝对或滑动过期的项。为已删除的项注册的任何回调都将被传递为已过期的删除原因。

If removing expired entries is insufficient to reach the specified trim percentage, additional entries will be removed from the cache based on a least-recently used (LRU) algorithm until the requested trim percentage is reached.

如果删除过期的条目不足以达到指定的修剪百分比,那么将根据最近使用的(LRU)算法从缓存中删除额外的条目,直到达到请求的修剪百分比。

But two other users reported it doesnt work on same page so I guess you are stuck with Remove() http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.trim.aspx

但是另外两个用户报告说它不能在同一个页面上工作,所以我猜你被删除了()http://msdn.microsoft.com/en- us/library/system.runtime.memorycache.trim.aspx

Update However I see no mention of it being singleton or otherwise unsafe to have multiple instances so you should be able to overwrite your reference.

但是,我没有看到更新单例或具有多个实例不安全,因此应该能够覆盖引用。

But if you need to free the memory from the Default instance you will have to clear it manually or destroy it permanently via dispose (rendering it unusable).

但是,如果需要从默认实例中释放内存,则必须手动清除内存,或者通过dispose(使其不可用)永久销毁内存。

Based on your question you could make your own singleton-imposing class returning a Memorycache you may internally dispose at will.. Being the nature of a cache :-)

根据您的问题,您可以创建自己的、强制的类,返回一个内存缓存,您可以在内部随意配置它。成为缓存的本质:-)

#2


27  

I was struggling with this at first. MemoryCache.Default.Trim(100) does not work (as discussed). Trim is a best attempt, so if there are 100 items in the cache, and you call Trim(100) it will remove the ones least used.

一开始我还在纠结这个问题。MemoryCache.Default.Trim(100)不工作(如前所述)。Trim是最好的尝试,因此如果缓存中有100个条目,并且您调用Trim(100),它将删除最不常用的条目。

Trim returns the count of items removed, and most people expect that to remove all items.

修剪返回删除项的计数,大多数人期望删除所有项。

This code removes all items from MemoryCache for me in my xUnit tests with MemoryCache.Default. MemoryCache.Default is the default Region.

这段代码为我在使用MemoryCache. default的xUnit测试中从MemoryCache删除所有的项。MemoryCache。默认是默认区域。

foreach (var element in MemoryCache.Default)
{
    MemoryCache.Default.Remove(element.Key);
}

#3


7  

Here's is what I had made for something I was working on...

这是我为我正在做的东西做的东西……

public void Flush()
{
    List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
    foreach (string cacheKey in cacheKeys)
    {
        MemoryCache.Default.Remove(cacheKey);
    }
}

#4


2  

The details in @stefan's answer detail the principle; here's how I'd do it.

@stefan回答中的细节详细说明了原则;我是这么做的。

One should synchronise access to the cache whilst recreating it, to avoid the race condition of client code accessing the cache after it is disposed, but before it is recreated.

在重新创建缓存时,应该同步对缓存的访问,以避免客户端代码在处理缓存之后(但在重新创建缓存之前)访问缓存的竞争条件。

To avoid this synchronisation, do this in your adapter class (which wraps the MemoryCache):

为了避免这种同步,请在您的适配器类(它封装了MemoryCache)中这样做:

public void clearCache() {
  var oldCache = TheCache;
  TheCache = new MemoryCache("NewCacheName", ...);
  oldCache.Dispose();
  GC.Collect();
}

This way, TheCache is always in a non-disposed state, and no synchronisation is needed.

这样,请求始终处于非处理状态,不需要同步。

#5


0  

I ran into this problem too. .Dispose() did something quite different than what I expected.

我也遇到了这个问题。. dispose()做了一些与我预期完全不同的事情。

Instead, I added a static field to my controller class. I did not use the default cache, to get around this behavior, but created a private one (if you want to call it that). So my implementation looked a bit like this:

相反,我向控制器类添加了一个静态字段。我没有使用默认缓存来绕过这种行为,而是创建了一个私有缓存(如果您想这样称呼它的话)。我的实现是这样的

public class MyController : Controller
{

    static MemoryCache s_cache = new MemoryCache("myCache");

    public ActionResult Index()
    {

        if (conditionThatInvalidatesCache)
        {
            s_cache = new MemoryCache("myCache");
        }

        String s = s_cache["key"] as String;

        if (s == null)
        {
            //do work
            //add to s_cache["key"]
        }

        //do whatever next
    }
}

#6


0  

Check out this post, and specifically, the answer that Thomas F. Abraham posted. It has a solution that enables you to clear the entire cache or a named subset.

看看这篇文章,尤其是托马斯·f·亚伯拉罕(Thomas F. Abraham)发布的答案。它有一个解决方案,可以让您清除整个缓存或指定的子集。

The key thing here is:

这里的关键是:

// Cache objects are obligated to remove entry upon change notification.
base.OnChanged(null);

I've implemented this myself, and everything seems to work just fine.

我自己实现了这个,一切似乎都很好。