Comment effacer MemoryCache?

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 supprimer. Quel est le moyen le plus rapide de le faire? Dois-je parcourir tous les éléments et les retirer un par un ou existe-t-il un meilleur moyen?

Supprimez le MemoryCache existant et créez un nouvel object MemoryCache.

Le problème de l’énumération

La section MemoryCache.GetEnumerator () Remarques avertit: “La récupération d’un énumérateur pour une instance MemoryCache est une opération nécessitant beaucoup de ressources et de blocage. Par conséquent, l’énumérateur ne doit pas être utilisé dans les applications de production.”

Voici pourquoi , expliqué dans le pseudocode de l’implémentation 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 

Étant donné que l’implémentation divise le cache sur plusieurs objects Dictionary, elle doit tout rassembler dans une seule collection afin de renvoyer 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 aux objects de clé et de valeur internes d’origine afin que vos valeurs de données mises en cache ne soient pas dupliquées.

L’avertissement dans la documentation est correct. Évitez GetEnumerator () – y compris toutes les réponses ci-dessus qui utilisent des requêtes LINQ.

Une solution meilleure et plus flexible

Voici un moyen efficace de vider le cache en se basant simplement sur l’infrastructure de surveillance des modifications existante. Il offre également la possibilité d’effacer soit l’intégralité du cache, soit 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 ssortingng Name { get; private set; } public SignaledChangeEventArgs(ssortingng name = null) { this.Name = name; } } ///  /// Cache change monitor that allows an app to fire a change notification /// to all associated cache items. ///  public class SignaledChangeMonitor : ChangeMonitor { // Shared across all SignaledChangeMonitors in the AppDomain private static event EventHandler Signaled; private ssortingng _name; private ssortingng _uniqueId = Guid.NewGuid().ToSsortingng("N", CultureInfo.InvariantCulture); public override ssortingng UniqueId { get { return _uniqueId; } } public SignaledChangeMonitor(ssortingng name = null) { _name = name; // Register instance with the shared event SignaledChangeMonitor.Signaled += OnSignalRaised; base.InitializationComplete(); } public static void Signal(ssortingng 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 (ssortingng.IsNullOrWhiteSpace(e.Name) || ssortingng.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; } } } 

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

La solution de contournement est la suivante:

 List cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList(); foreach (ssortingng cacheKey in cacheKeys) { MemoryCache.Default.Remove(cacheKey); } 
 var cacheItems = cache.ToList(); foreach (KeyValuePair a in cacheItems) { cache.Remove(a.Key); } 

Si la performance n’est pas un problème, alors ce beau one-liner fera l’affaire:

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

Il semble qu’il y ait une méthode Trim .

Donc, pour effacer tous les contenus que vous venez de faire

 cache.Trim(100) 

EDIT: après avoir creusé plus, il semble que regarder dans Trim ne vaut pas votre temps

https://connect.microsoft.com/VisualStudio/feedback/details/831755/memorycache-sortingm-method-doesnt-evict-100-of-the-items

Comment puis-je effacer un System.Runtime.Caching.MemoryCache

Vous pourriez aussi faire quelque chose comme ceci:

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

Ran à travers ceci, et basé là-dessus, 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)); } 

une version un peu améliorée de la réponse magritte.

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