Подтвердить что ты не робот

Как очистить System.Runtime.Caching.MemoryCache

Я использую System.Runtime.Caching.MemoryCache для хранения элементов, которые никогда не истекают. Однако иногда мне нужна возможность очистить весь кеш. Как это сделать?

Я задал аналогичный вопрос здесь относительно того, могу ли я перечислить кеш, но это плохая идея, поскольку его необходимо синхронизировать во время перечисления.

Я пробовал использовать .Trim(100), но это не работает вообще.

Я попытался получить список всех ключей через Linq, но потом я вернулся туда, где начал, потому что выселение предметов по одному может легко привести к условиям гонки.

Я думал хранить все ключи, а затем выдавал .Remove(key) для каждого из них, но там также подразумевается состояние гонки, поэтому мне нужно заблокировать доступ к списку ключей, и все становится беспорядочным еще раз.

Затем я подумал, что должен иметь возможность вызывать .Dispose() во всем кеше, но я не уверен, что это лучший подход из-за того, как он реализован.

Использование ChangeMonitors не является вариантом для моего дизайна и не является излишне сложным для такого тривиального требования.

Итак, как полностью очистить кеш?

4b9b3361

Ответ 1

Вы не должны вызывать dispose в члене Default MemoryCache, если вы хотите больше использовать его:

Состояние кеша установлено так, чтобы указать, что кеш расположен. Любая попытка вызвать общедоступные методы кэширования, которые изменяют состояние кеш, такие как методы, которые добавляют, удаляют или извлекают кеш может привести к неожиданному поведению. Например, если вы вызываете Установите метод после того, как кэш будет удален, возникает ошибка no-op. если ты попытаться извлечь элементы из кеша, метод Get всегда будет ничего не возвращай. http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.dispose.aspx

О Trim, он должен работать:

Свойство Trim сначала удаляет записи, которые превысили либо абсолютное, либо скользящее окончание. Любые обратные вызовы, которые зарегистрированы для удаляемых предметов будет передана удаленная причина "Истек".

Если удаление истекших записей недостаточно для достижения указанного процента триммера, дополнительные записи будут удалены из кеша основанный на алгоритме наименее недавно использованного (LRU) до достигнута скидка.

Но два других пользователя сообщили, что он не работает на одной странице, поэтому я думаю, что вы застряли в Remove() http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.trim.aspx

Update Однако я не вижу упоминания о том, что это singleton или иначе небезопасно, чтобы иметь несколько экземпляров, чтобы вы могли перезаписать свою ссылку.

Но если вам нужно освободить память из экземпляра по умолчанию, вам придется очистить ее вручную или уничтожить ее навсегда с помощью утилиты (рендеринг ее неприменимо).

Основываясь на вашем вопросе, вы можете сделать свой собственный однопользовательский класс, возвращающий Memorycache, который вы можете внутренне распоряжаться по своему усмотрению. Будучи природой кэш: -)

Ответ 2

Сначала я боролся с этим. MemoryCache.Default.Trim(100) не работает (как обсуждалось). Trim - лучшая попытка, поэтому, если в кеше есть 100 элементов, и вы вызываете Trim (100), он удаляет наименее используемые.

Trim возвращает количество удаленных элементов, и большинство людей ожидает, что удалит все элементы.

Этот код удаляет все элементы из MemoryCache для меня в моих тестах xUnit с помощью MemoryCache.Default. MemoryCache.Default - это регион по умолчанию.

foreach (var element in MemoryCache.Default)
{
    MemoryCache.Default.Remove(element.Key);
}

Ответ 3

Вот что я сделал для чего-то, над чем я работал...

public void Flush()
{
    List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
    foreach (string cacheKey in cacheKeys)
    {
        MemoryCache.Default.Remove(cacheKey);
    }
}

Ответ 4

Подробности в @stefan отвечают детали принципа; вот как я это сделаю.

Необходимо синхронизировать доступ к кешу при его воссоздании, чтобы избежать состояния гонки клиентского кода, доступ к кешу после его размещения, но до его воссоздания.

Чтобы избежать этой синхронизации, сделайте это в своем классе адаптера (который обертывает MemoryCache):

public void clearCache() {
  var oldCache = TheCache;
  TheCache = new MemoryCache("NewCacheName", ...);
  oldCache.Dispose();
  GC.Collect();
}

Таким образом, TheCache всегда находится в неустановленном состоянии, и никакая синхронизация не требуется.

Ответ 5

Я столкнулся с этой проблемой..Dispose() сделал что-то совсем другое, чем ожидалось.

Вместо этого я добавил статическое поле в класс контроллера. Я не использовал кеш по умолчанию, чтобы обойти это поведение, но создал частный (если вы хотите его назвать). Итак, моя реализация выглядела примерно так:

public class MyController : Controller
{

    static MemoryCache s_cache = new MemoryCache("myCache");

    public ActionResult Index()
    {

        if (conditionThatInvalidatesCache)
        {
            s_cache = new MemoryCache("myCache");
        }

        String s = s_cache["key"] as String;

        if (s == null)
        {
            //do work
            //add to s_cache["key"]
        }

        //do whatever next
    }
}

Ответ 6

Отметьте этот пост и, в частности, ответ, который Thomas F. Abraham опубликовал. Он имеет решение, которое позволяет очистить весь кеш или именованное подмножество.

Ключевое значение здесь:

// Cache objects are obligated to remove entry upon change notification.
base.OnChanged(null);

Я реализовал это сам, и все работает нормально.