web-dev-qa-db-fra.com

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 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?

89
Retrocoder

Dispose le MemoryCache existant et créez un nouvel objet MemoryCache.

55
GvS

Le problème de l'énumération

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.

Une solution meilleure et plus flexible

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;
        }
    }
}
54
Thomas F. Abraham

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

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);
}
33
magritte
var cacheItems = cache.ToList();

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

Si les performances ne sont pas un problème, ce Nice One-Liner fera l'affaire:

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

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.

https://connect.Microsoft.com/VisualStudio/feedback/details/831755/memorycache-trim-method-dhodnt-evict-100-of-the-items

Comment effacer un System.Runtime.Caching.MemoryCache

7
bottlenecked

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
3
Kevin

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));
    }
2
Pedro G. Dias

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);
}
0
Khachatur