it-swarm-pt.tech

Como limpar MemoryCache?

Eu criei um cache usando a classe MemoryCache. Eu adiciono alguns itens a ele, mas quando preciso recarregar o cache, quero limpá-lo primeiro. Qual é a maneira mais rápida de fazer isso? Devo percorrer todos os itens e removê-los um de cada vez ou existe uma maneira melhor?

86
Retrocoder

Dispose o MemoryCache existente e crie um novo objeto MemoryCache.

54
GvS

O problema com enumeração

A seção MemoryCache.GetEnumerator () Remarks adverte: "A recuperação de um enumerador para uma instância de MemoryCache é uma operação intensiva em recursos e de bloqueio. Portanto, o enumerador não deve ser usado em aplicativos de produção."

Aqui está o porquê , explicado no pseudocódigo da implementação 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

Como a implementação divide o cache em vários objetos Dictionary, deve reunir tudo em uma única coleção para devolver um enumerador. Toda chamada para GetEnumerator executa o processo de cópia completo detalhado acima. O recém-criado Dicionário contém referências à chave interna original e aos objetos de valor, para que seus valores reais de dados em cache não sejam duplicados.

O aviso na documentação está correto. Evite GetEnumerator () - incluindo todas as respostas acima que usam consultas LINQ.

Uma solução melhor e mais flexível

Aqui está uma maneira eficiente de limpar o cache que simplesmente se baseia na infraestrutura de monitoramento de alterações existente. Ele também oferece a flexibilidade de limpar o cache inteiro ou apenas um subconjunto nomeado e não possui nenhum dos problemas discutidos acima.

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

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

A solução alternativa é:

List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
    MemoryCache.Default.Remove(cacheKey);
}
32
magritte
var cacheItems = cache.ToList();

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

Se o desempenho não for um problema, esta linha agradável fará o truque:

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

Parece que existe um método Trim .

Então, para limpar todo o conteúdo que você faria

cache.Trim(100)

EDIT: depois de cavar um pouco mais, parece que olhar para o Trim não vale o seu tempo

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

Como limpo um System.Runtime.Caching.MemoryCache

7
bottlenecked

Você também pode fazer algo assim:


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

Deparei com isso e, com base nisso, escrevi um método claro paralelo um pouco mais eficaz:

    public void ClearAll()
    {
        var allKeys = _cache.Select(o => o.Key);
        Parallel.ForEach(allKeys, key => _cache.Remove(key));
    }
2
Pedro G. Dias

versão um pouco melhorada da resposta 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);
}
0
Khachatur