c# - memory cache.net framework
Cómo borrar MemoryCache? (9)
El problema con la enumeración
La sección Observaciones de MemoryCache.GetEnumerator () advierte: "Recuperar un enumerador para una instancia de MemoryCache es una operación de uso intensivo y de bloqueo. Por lo tanto, el enumerador no se debe usar en aplicaciones de producción".
Este es el motivo , explicado en el pseudocódigo de la implementación de 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
Dado que la implementación divide el caché en varios objetos del diccionario, debe reunir todo en una sola colección para devolver un enumerador. Cada llamada a GetEnumerator ejecuta el proceso de copia completo detallado anteriormente. El diccionario creado recientemente contiene referencias a la clave interna original y los objetos de valor, por lo que sus valores de datos en caché no se duplican.
La advertencia en la documentación es correcta. Evite GetEnumerator (), incluidas todas las respuestas anteriores que utilizan consultas LINQ.
Una solución mejor y más flexible
Aquí hay una forma eficiente de borrar el caché que simplemente se basa en la infraestructura de monitoreo de cambios existente. También proporciona la flexibilidad para borrar todo el caché o solo un subconjunto con nombre y no tiene ninguno de los problemas mencionados anteriormente.
// 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;
}
}
}
He creado un caché usando la clase MemoryCache. Le agrego algunos elementos, pero cuando necesito volver a cargar el caché, quiero borrarlo primero. ¿Cuál es la forma más rápida de hacer esto? ¿Debería recorrer todos los elementos y eliminarlos uno a la vez o hay una forma mejor?
La solución alternativa es:
List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
MemoryCache.Default.Remove(cacheKey);
}
Me encontré con esto y, basado en él, escribí un método claro paralelo más ligero:
public void ClearAll()
{
var allKeys = _cache.Select(o => o.Key);
Parallel.ForEach(allKeys, key => _cache.Remove(key));
}
Parece que hay un método Trim .
Entonces, para borrar todo lo que harías
cache.Trim(100)
EDITAR: después de cavar un poco más, parece que mirar en Trim no vale su tiempo
Si el rendimiento no es un problema, entonces este buen one-liner hará el truco:
cache.ToList().ForEach(a => cache.Remove(a.Key));
También podrías hacer algo como esto:
Dim _Qry = (From n In CacheObject.AsParallel()
Select n).ToList()
For Each i In _Qry
CacheObject.Remove(i.Key)
Next
una versión mejorada de la respuesta de magritte.
var cacheKeys = MemoryCache.Default.Where(kvp.Value is MyType).Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
MemoryCache.Default.Remove(cacheKey);
}
Dispose
el MemoryCache existente y cree un nuevo objeto MemoryCache.
var cacheItems = cache.ToList();
foreach (KeyValuePair<String, Object> a in cacheItems)
{
cache.Remove(a.Key);
}