Ответ 1
Dispose
существующий MemoryCache и создать новый объект MemoryCache.
Я создал кеш, используя класс MemoryCache. Я добавляю некоторые элементы к нему, но когда мне нужно перезагрузить кеш, я хочу сначала его очистить. Каков самый быстрый способ сделать это? Должен ли я перебирать все элементы и удалять их по одному или есть лучший способ?
Dispose
существующий MemoryCache и создать новый объект MemoryCache.
Блок памяти MemoryCache.GetEnumerator() предупреждает: "Извлечение перечислителя для экземпляра MemoryCache является ресурсоемкой и блокирующей операцией., перечислитель не должен использоваться в производственных приложениях."
Вот почему, объясненный в псевдокоде реализации GetEnumerator():
Create a new Dictionary object (let 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 выполняет полный процесс копирования, описанный выше. Недавно созданный словарь содержит ссылки на исходный внутренний ключ и объекты значений, поэтому ваши фактические значения кэшированных данных не дублируются.
Предупреждение в документации правильное. Избегайте 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;
}
}
}
Обходной путь:
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));
Кажется, что существует метод Trim.
Итак, чтобы очистить все содержимое, которое вы просто сделали
cache.Trim(100)
EDIT: после копания еще немного, кажется, что просмотр Trim не стоит вашего времени
Вы также можете сделать что-то вроде этого:
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));
}
немного улучшенная версия ответа magritte.
var cacheKeys = MemoryCache.Default.Where(kvp.Value is MyType).Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
MemoryCache.Default.Remove(cacheKey);
}