如何清除内存缓存?

我已经使用 MemoryCache 类创建了一个缓存。我向它添加了一些项目,但是当我需要重新加载缓存时,我想先清除它。最快的方法是什么?我应该循环遍历所有的项目,并删除他们一次或有一个更好的方法吗?

117418 次浏览

Dispose the existing MemoryCache and create a new MemoryCache object.

你也可以这样做:


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


foreach (KeyValuePair<String, Object> a in cacheItems)
{
cache.Remove(a.Key);
}

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

The workaround is:

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

马格里特答案的改进版。

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

如果性能不是问题,那么这句俏皮话就能解决问题:

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

The problem with enumeration

MemoryCache.GetEnumerator() Remarks section警告说: “检索 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

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

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

A better and more flexible solution

这里有一种清除缓存的有效方法,它只是构建在现有的变更监视基础设施之上。它还提供了清除整个缓存或仅清除命名子集的灵活性,没有上面讨论的任何问题。

// 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;
}
}
}

似乎有一个 修剪方法。

所以要清除所有内容,你只需要

cache.Trim(100)

编辑: 经过深入调查,似乎不值得你花时间去调查 Trim

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

如何清除系统。运行时。缓存。内存缓存

Ran across this, and based on it, wrote a slightly more effective, parallel clear method:

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

您可以释放内存缓存。默认缓存,然后将私有字段 singleton 重新设置为 null,使其重新创建 MemoryCache。默认。

       var field = typeof(MemoryCache).GetField("s_defaultCache",
BindingFlags.Static |
BindingFlags.NonPublic);
field.SetValue(null, null);

我只对清除缓存感兴趣,并且在使用 c # GlobalCachingProvider 时发现这是一个选项

                var cache = GlobalCachingProvider.Instance.GetAllItems();
if (dbOperation.SuccessLoadingAllCacheToDB(cache))
{
cache.Clear();
}

这种讨论也在这里进行: Https://learn.microsoft.com/en-us/answers/answers/983399/view.html

I wrote an answer there and I'll transcribe it here:

using System.Collections.Generic;
using Microsoft.Extensions.Caching.Memory;
using ServiceStack;


public static class IMemoryCacheExtensions
{
static readonly List<object> entries = new();


/// <summary>
/// Removes all entries, added via the "TryGetValueExtension()" method
/// </summary>
/// <param name="cache"></param>
public static void Clear(this IMemoryCache cache)
{
for (int i = 0; i < entries.Count; i++)
{
cache.Remove(entries[i]);
}
entries.Clear();
}


/// <summary>
/// Use this extension method, to be able to remove all your entries later using "Clear()" method
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="cache"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TryGetValueExtension<TItem>(this IMemoryCache cache, object key, out TItem value)
{
entries.AddIfNotExists(key);


if (cache.TryGetValue(key, out object result))
{
if (result == null)
{
value = default;
return true;
}


if (result is TItem item)
{
value = item;
return true;
}
}


value = default;
return false;
}
}