Как удалить просроченные элементы из кеша?

У меня есть хороший маленький класс, который действует как кеш. Каждый элемент имеет срок действия TimeSpan или DateTime. Каждый раз, когда предпринимается попытка доступа к элементу в кеше, проверяется срок действия элемента, и если он истек, элемент удаляется из кеша и ничего не возвращается.

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

Какова хорошая методология для удаления таких элементов из кеша?

Должен ли я иметь фоновый поток, бесконечно перечисляющий каждый элемент в кеше, чтобы проверить, не истек ли срок его действия?


person core    schedule 26.09.2008    source источник
comment
Это кеш фиксированного размера? Если это так, я не вижу проблем с оставлением элементов в кеше.   -  person Ryan Guest    schedule 26.09.2008


Ответы (5)


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

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

person Kilhoffer    schedule 26.09.2008

Лучший код — это отсутствие кода. Вместо этого используйте кеш ASP.NET. Вы можете ссылаться на него как на System.Web.HttpRuntime.Cache в любом приложении, а не только в веб-приложениях.

person Joe    schedule 26.09.2008
comment
Что, если сборка использует HttpRuntime.Cache в двух разных местах? Они используют один и тот же кеш, верно? В таком случае это не сработает, к сожалению. Он уже используется, и поэтому я не могу гарантировать, что мои предметы не будут удалены. - person core; 03.10.2008
comment
Я не понимаю вашего комментария. Для каждого AppDomain существует один объект HttpRuntime.Cache. Если вы вставляете элементы в кэш в двух разных местах, вы должны использовать разные ключи — это справедливо для любого решения. Можете ли вы уточнить? - person Joe; 03.10.2008
comment
Текущей альтернативой, если вы можете использовать платформу 4.0, является Кэш памяти. Это нарушает зависимость от ASP.Net, и у вас может быть несколько экземпляров, но для этого требуется полная платформа 4.0. - person Kevin Pullin; 20.02.2011

Вы можете внедрить стратегию LRU (наименее недавно использованная), сортировать элементы по времени доступа, когда новый элемент вставляется в кеш и кеш заполняется, вы удаляете последний элемент в этом список. См. алгоритмы кэширования в Википедии.

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

person Harald Scheirich    schedule 26.09.2008

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

Однако ответ Харальда Шейриха лучше, если вы не возражаете против того, что объекты висят вечно, когда кеш не обновляется.

person OregonGhost    schedule 26.09.2008

Вы можете удалить достаточно старые элементы из кеша при первом доступе через 1 минуту после последней очистки элементов.

private DateTime nextFlush;
public object getItem(object key)
{
  DateTime now = DateTime.Now
  if (now > nextFlush)
  {
    Flush();
    nextFlush = now.AddMinutes(1)
  }
  return fetchItem(key);
}
person Amy B    schedule 26.09.2008