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





Вы можете реализовать стратегию LRU (Least Recently Used), сохраняя ваши элементы отсортированными по времени доступа, когда новый элемент вставляется в кеш и, кеш заполнен, вы исключили элемент, который находится последним в этом списке. См. Алгоритмы кеширования в Википедии.
Если вы хотите, чтобы срок действия истек немедленно, я все равно буду делать это только при доступе к вещам. Т.е. когда к объекту кеша обращаются и его время истекло, восстановите его.
Вы также можете при любом изменении кеша (повторно) запустить таймер с интервалом, установленным на ближайшую временную метку истечения срока. Это не будет точным до миллисекунд и будет зависеть от работы насоса сообщений, но не требует больших ресурсов.
Ответ Харальда Шейриха лучше, если вы не возражаете, что объекты торчат вечно, когда кеш не обновляется.
Вы можете очистить подходящие старые элементы из кеша при первом доступе через 1 минуту после последней очистки элементов.
private DateTime nextFlush;
public object getItem(object key)
{
DateTime now = DateTime.Now
if (now > nextFlush)
{
Flush();
nextFlush = now.AddMinutes(1)
}
return fetchItem(key);
}
По моему опыту, поддержание настраиваемого механизма кэширования стало для меня труднее, чем оно того стоило. Есть несколько библиотек, которые уже решили эти проблемы. Я бы предложил использовать один из них. Популярной в .Net является Enterprise Library, хотя у меня ограниченный опыт работы с ее возможностями кэширования.
Если вам необходимо использовать настраиваемый механизм кэширования, я не вижу проблем с предложенной вами идеей бдительного потока. То есть, если ваше приложение является серверным, а не веб-приложением. Если это веб-приложение, у вас уже есть скользящий срок действия. Затем вы можете просто обернуть его строго типизированной оболочкой, чтобы каждый раз не ссылаться на элементы кеша по ключу.
Лучший код - это отсутствие кода. Вместо этого используйте кеш ASP.NET. Вы можете ссылаться на него как на System.Web.HttpRuntime.Cache в любом приложении, а не только в веб-приложениях.
Что, если сборка использует HttpRuntime.Cache в двух разных местах? У них один и тот же кеш, верно? В этом случае, к сожалению, это не сработает. Он уже используется, поэтому я не могу гарантировать, что мои предметы не будут удалены.
Я не понимаю вашего комментария. Для каждого домена приложения существует один объект HttpRuntime.Cache. Если вы вставляете элементы в кеш в два разных места, вы должны использовать разные ключи - это верно для любого решения. Вы можете уточнить?
Текущая альтернатива, если вы можете использовать структуру 4.0, - это ПамятьКэш. Это нарушает зависимость от ASP.Net, и у вас может быть несколько экземпляров, но требуется полная структура 4.0.
Это кеш фиксированного размера? Если это так, я не вижу проблем с сохранением элементов в кеше.