J'ai créé un cache en utilisant la classe MemoryCache. J'y ajoute des éléments, mais lorsque je dois recharger le cache, je veux d'abord le vider. Quel est le moyen le plus rapide de faire cela? Dois-je parcourir tous les éléments et les supprimer un à la fois ou existe-t-il un meilleur moyen?
Dispose
le MemoryCache existant et créez un nouvel objet MemoryCache.
La section Remarques MemoryCache.GetEnumerator () avertit: "La récupération d'un énumérateur pour une instance MemoryCache est une opération qui nécessite beaucoup de ressources et est ardue. Par conséquent, l'énumérateur ne doit pas être utilisé dans des applications de production."
Voici pourquoi , expliqué dans le pseudocode de l'implémentation 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
Étant donné que l'implémentation divise le cache en plusieurs objets Dictionnaire, elle doit tout réunir dans une seule collection pour pouvoir restituer un énumérateur. Chaque appel à GetEnumerator exécute le processus de copie complet détaillé ci-dessus. Le dictionnaire nouvellement créé contient des références à la clé interne d'origine et aux objets de valeur. Par conséquent, vos valeurs de données en cache réelles ne sont pas dupliquées.
L'avertissement dans la documentation est correct. Évitez GetEnumerator () - en incluant toutes les réponses ci-dessus qui utilisent des requêtes LINQ.
Voici un moyen efficace d'effacer le cache qui repose simplement sur l'infrastructure de surveillance des modifications existante. Il offre également la possibilité d'effacer le cache entier ou seulement un sous-ensemble nommé et ne présente aucun des problèmes décrits ci-dessus.
// 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;
}
}
}
La solution de contournement est la suivante:
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);
}
Si les performances ne sont pas un problème, ce Nice One-Liner fera l'affaire:
cache.ToList().ForEach(a => cache.Remove(a.Key));
Il semble qu'il existe une méthode Trim .
Donc, pour effacer tout le contenu que vous venez de faire
cache.Trim(100)
EDIT: après avoir creusé un peu plus, il semble que regarder dans Trim ne vaut pas la peine.
Vous pouvez aussi faire quelque chose comme ça:
Dim _Qry = (From n In CacheObject.AsParallel()
Select n).ToList()
For Each i In _Qry
CacheObject.Remove(i.Key)
Next
A traversé cela, et basé sur celle-ci, a écrit une méthode claire, légèrement plus efficace et parallèle:
public void ClearAll()
{
var allKeys = _cache.Select(o => o.Key);
Parallel.ForEach(allKeys, key => _cache.Remove(key));
}
version un peu améliorée de magritte answer.
var cacheKeys = MemoryCache.Default.Where(kvp.Value is MyType).Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
MemoryCache.Default.Remove(cacheKey);
}