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

С#: как реализовать интеллектуальный кеш

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

Простой пример последнего:

public static class Cache
{
    private static Dictionary<string, PropertyChangedEventArgs> cache;
    static Cache()
    {
        cache = new Dictionary<string, PropertyChangedEventArgs>();
    }
    public static PropertyChangedEventArgs GetPropertyChangedEventArgs(
        string propertyName)
    {
        if (cache.ContainsKey(propertyName))
            return cache[propertyName];

        return cache[propertyName] = new PropertyChangedEventArgs(propertyName);
    }
}

Но будет ли это работать хорошо? Например, если бы у нас была вся загрузка разных имен свойств, это означало бы, что у нас будет огромный кеш, в котором никогда не будет сбора мусора или чего-то еще. Я представляю, что то, что кэшируется, - это большие значения, и если приложение является долговременным, это может стать проблемой... или что вы думаете? Как должен быть реализован хороший кеш? Является ли это достаточно хорошим для большинства целей? Любые примеры некоторых хороших реализаций кэша, которые не так сложно понять или слишком сложно реализовать?

4b9b3361

Ответ 1

Вы можете обернуть каждый из ваших кешированных элементов в WeakReference. Это позволило бы GC восстановить элементы if-and-when required, однако это не дает вам какого-либо подробного контроля, когда элементы будут исчезать из кеша, или вы сможете реализовать явные политики истечения срока действия и т.д.

(Ха! Я только заметил, что пример, приведенный на странице

Ответ 2

Это большая проблема, вам нужно определить область проблемы и применить правильные методы. Например, как бы вы описали истечение срока действия объектов? Застывают ли они за определенный промежуток времени? Неужели они устаревают от внешнего события? Как часто это происходит? Кроме того, сколько у вас объектов? Наконец, сколько стоит генерировать объект?

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

Следующий слой может ограничивать количество объектов и использовать неявную политику истечения срока действия, такую ​​как LRU (последний раз используется). Для этого вы обычно используете двойной список в дополнение к вашему словарю, и каждый раз, когда объекты обращаются к нему, он перемещается в начало списка. Затем, если вам нужно добавить новый объект, но он превысит ваш лимит полных объектов, вы удалите его из задней части списка.

Далее вам может потребоваться принудительное явное истечение, основанное на времени или на каком-то внешнем стимуле. Это потребует, чтобы у вас было какое-то событие истечения срока действия, которое можно было бы назвать.

Как вы видите, в кешировании много дизайна, поэтому вам нужно правильно понимать свой домен и инженер. Вы не представили достаточно подробностей для меня, чтобы обсудить специфику, я чувствовал.

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

Ответ 3

Похоже, что .NET 4.0 теперь поддерживает System.Runtime.Caching для кеширования многих типов вещей. Вы должны сначала изучить это, вместо того, чтобы повторно изобретать колесо. Подробнее:

http://msdn.microsoft.com/en-us/library/system.runtime.caching%28VS.100%29.aspx

Ответ 4

Это хорошая дискуссия, но в зависимости от вашего приложения, вот несколько советов:

Вы должны определить максимальный размер кеша, что делать со старыми элементами, если ваш кеш заполнен, иметь стратегию очистки, определить время жизни объекта в кеше, может ли ваш кеш быть/должен сохраняться где-то еще эта память, в случае ненормального завершения приложения,...

Ответ 5

Это обычная проблема, которая имеет множество решений в зависимости от потребностей вашего приложения. Настолько распространено, что Microsoft выпустила целую библиотеку для ее решения. Вы должны проверить Microsoft Velocity, прежде чем сворачивать свой собственный кеш. http://msdn.microsoft.com/en-us/data/cc655792.aspx Надеюсь на эту помощь.

Ответ 6

Вы можете использовать WeakReference, но если ваш объект не так велик, как не потому, что WeakReference будет занимать больше памяти, чем сам объект, что не является хорошей техникой. Кроме того, если объект является кратковременным использованием, когда он никогда не сделает его поколением 1 из поколения 0 в GC, нет необходимости в WeakReference, но интерфейс IDisposable на объекте будет иметь с выпуском SuppressFinalize.

Если вы хотите контролировать время жизни, вам нужен таймер, чтобы снова обновить datetime/timespan желаемое значениеExpirationTime для объекта в вашем кеше.

Важно то, что если объект большой, тогда выберите, что WeakReference else использует сильную ссылку. Кроме того, вы можете установить емкость в словаре и создать очередь для запроса дополнительных объектов в вашем временном бин-сериализации объекта и загрузки его, когда в словаре есть место, затем очистите его из каталога temp.