System.Runtime.Caching.MemoryCache vs HttpRuntime.Cache - есть ли различия?

85

Мне интересно, есть ли какие-либо различия между MemoryCacheи HttpRuntime.Cache, какой из них предпочтителен в проектах ASP.NET MVC?

Насколько я понимаю, оба являются потокобезопасными, API на первый взгляд более или менее одинаков, поэтому есть ли разница, когда использовать какой?

Гедрюс
источник

Ответы:

82

HttpRuntime.Cacheполучает Cacheдля текущего приложения.

MemoryCacheКласс похож на ASP.NET Cacheкласса.

MemoryCacheКласс имеет много свойств и методов для доступа к кэш - памяти , который будет вам знакомо , если вы использовали ASP.NET Cacheкласс.

Основное различие между HttpRuntime.Cacheи MemoryCacheзаключается в том, что последний был изменен, чтобы сделать его пригодным для использования приложениями .NET Framework, которые не являются приложениями ASP.NET.

Для дополнительного чтения:

Обновить :

По отзывам пользователей, иногда блог Джона Дэвиса не работает, поэтому я поместил всю статью в виде изображения. Пожалуйста, посмотрите это.

Примечание: если что-то непонятно, просто нажмите на изображение, после чего оно откроется в браузере, а затем нажмите еще раз для увеличения :)

введите описание изображения здесь

Сампатх
источник
Эта статья Джона Дэвиса действительно хорошо читается - ясные плюсы и минусы в одном месте.
Giedrius
абсолютно все в одном месте. Кроме того, Дэвис также упомянул 4 различных метода кеширования.
Sampath
2
@Spikeh У меня нормально загружается.
user247702
1
@Stijn Спасибо, на днях не загружался, но теперь вернулся :)
Спайк,
1
@sampath теперь работает. Вчера казалось, что сайт взломали. Спасибо за вашу помощь!
Бага
25

Вот статья Джона Дэвиса. Чтобы сохранить удобочитаемость, я вырезаю уже устаревший раздел EntLib, вводную часть, а также заключение.


Кэш ASP.NET

ASP.NET или сборка System.Web.dll имеет механизм кэширования. Он никогда не предназначался для использования вне веб-контекста, но его можно использовать и за пределами Интернета, и он выполняет все вышеперечисленные действия по истечении срока действия в своего рода хэш-таблице.

После поиска в Google выяснилось, что довольно много людей, которые обсуждали встроенные функции кэширования в .NET, прибегали к использованию кеша ASP.NET в своих не-веб-проектах. Это уже не самая доступная и наиболее поддерживаемая встроенная система кэширования в .NET; В .NET 4 есть ObjectCache, о котором я расскажу позже. Microsoft всегда была непреклонна в том, что кеш ASP.NET не предназначен для использования вне Интернета. Но многие люди по-прежнему застревают в .NET 2.0 и .NET 3.5 и нуждаются в чем-то, с чем можно работать, и это работает для многих людей, хотя MSDN ясно говорит:

Примечание. Класс Cache не предназначен для использования вне приложений ASP.NET. Он был разработан и протестирован для использования в ASP.NET для обеспечения кэширования веб-приложений. В других типах приложений, таких как консольные приложения или приложения Windows Forms, кэширование ASP.NET может работать некорректно.

Класс для кэша ASP.NET - это System.Web.Caching.Cache в System.Web.dll. Однако вы не можете просто обновить объект Cache. Вы должны получить его из System.Web.HttpRuntime.Cache.

Cache cache = System.Web.HttpRuntime.Cache;

Работа с кешем ASP.NET описана в MSDN здесь .

Плюсы:

  1. Он встроен .
  2. Несмотря на синтаксис .NET 1.0, его довольно просто использовать.
  3. При использовании в веб-контексте он хорошо протестирован . Вне веб-контекстов, согласно поисковым запросам Google, обычно не известно, что он вызывает проблемы, несмотря на то, что Microsoft рекомендует против этого, если вы используете .NET 2.0 или более позднюю версию.
  4. Вы можете получать уведомления через делегата об удалении элемента, что необходимо, если вам нужно сохранить его в рабочем состоянии и вы не можете заранее установить приоритет элемента.
  5. Отдельные элементы имеют гибкость любого из (а), (б) или (в) методов истечения срока действия и удаления в списке методов удаления в верхней части этой статьи. Вы также можете связать истечение срока действия с наличием физического файла.

Минусы:

  1. Мало того, что он статичен, он только один . Вы не можете создать свой собственный тип с его собственным статическим экземпляром Cache. У вас может быть только одна корзина для всего приложения, и точка. Вы можете обернуть ведро своими собственными оболочками, которые делают такие вещи, как префиксы предварительного ввода в ключи и удаляют эти префиксы, когда вы извлекаете пары ключ / значение обратно. Но ведро осталось только одно. Все смешано. Это может быть настоящей неприятностью, если, например, у вас есть служба, которая должна отдельно кэшировать три или четыре разных типа данных. Это не должно быть большой проблемой для жалко простых проектов. Но если проект имеет значительную степень сложности из-за своих требований, кеша ASP.NET обычно недостаточно.
  2. Предметы могут исчезать волей-неволей. Многие люди не знают об этом - я не знал, пока не обновил свои знания об этой реализации кеширования. По умолчанию кеш ASP.NET предназначен для уничтожения элементов, когда он «чувствует» это так. Более конкретно, см. (C) в моем определении таблицы кеширования в верхней части этой статьи. Если другой поток в том же процессе работает с чем-то совершенно другим и выгружает высокоприоритетные элементы в кеш, то, как только .NET решает, что ему требуется некоторая память, он начнет уничтожать некоторые элементы в кеше в соответствии с их приоритеты, сначала более низкие приоритеты. Во всех описанных здесь примерах добавления элементов кэша используется приоритет по умолчанию, а не значение приоритета NotRemovable, которое предотвращает его удаление для целей очистки памяти, но все равно удаляет его в соответствии с политикой истечения срока действия.
  3. Ключ должен быть строкой. Если, например, вы кэшируете записи данных, в которых записи имеют длинный или целочисленный ключ, вы должны сначала преобразовать ключ в строку.
  4. Синтаксис устарел . Это синтаксис .NET 1.0, даже уродливее, чем ArrayList или Hashtable. Здесь нет ни дженериков, ни интерфейса IDictionary <>. В нем нет метода Contains (), нет коллекции ключей, нет стандартных событий; у него есть только метод Get () плюс индексатор, который делает то же самое, что и Get (), возвращая null, если совпадений нет, плюс Add (), Insert () (избыточный?), Remove () и GetEnumerator () .
  5. Игнорирует принцип СУХОЙ настройки поведения по умолчанию для истечения срока действия / удаления, чтобы вы могли забыть о них. Вы должны явно указать кешу, как вы хотите, чтобы элемент, который вы добавляете, истек или удалялся каждый раз, когда вы добавляете элемент.
  6. Невозможно получить доступ к деталям кеширования кэшированного элемента, таким как отметка времени, когда он был добавлен. Инкапсуляция здесь немного переборщила, что затрудняет использование кеша, когда в коде вы пытаетесь определить, должен ли кэшированный элемент быть недействительным для другого механизма кэширования (например, коллекции сеансов) или нет.
  7. События удаления не отображаются как события и должны отслеживаться во время добавления.
  8. И если я не сказал достаточно, Microsoft категорически не рекомендует использовать это вне Интернета. И если вы прокляты с .NET 1.1, вы не должны использовать его с какой-либо уверенностью в стабильности вне сети, так что не беспокойтесь.

.NET 4.0 ObjectCache / MemoryCache

Наконец, Microsoft реализовала абстрактный класс ObjectCache в последней версии .NET Framework и реализацию MemoryCache, которая наследует и реализует ObjectCache для целей в памяти в настройках, отличных от Интернета.

System.Runtime.Caching.ObjectCache находится в сборке System.Runtime.Caching.dll. Это абстрактный класс, который объявляет в основном те же интерфейсы в стиле .NET 1.0, которые находятся в кэше ASP.NET. System.Runtime.Caching.MemoryCacheявляется реализацией ObjectCache в памяти и очень похож на кеш ASP.NET с некоторыми изменениями.

Чтобы добавить элемент с скользящим сроком действия, ваш код будет выглядеть примерно так:

var config = new NameValueCollection();  
var cache = new MemoryCache("myMemCache", config);  
cache.Add(new CacheItem("a", "b"),  
    new CacheItemPolicy  
    {  
        Priority = CacheItemPriority.NotRemovable,  
        SlidingExpiration=TimeSpan.FromMinutes(30)  
    }); 

Плюсы:

  1. Он встроен и теперь поддерживается и рекомендован Microsoft за пределами Интернета.
  2. В отличие от кеша ASP.NET, вы можете создать экземпляр объекта MemoryCache.

    Примечание. Оно не обязательно должно быть статическим, но должно быть - это рекомендация Microsoft (см. Желтый цвет «Предупреждение») .

  3. По сравнению с интерфейсом кеша ASP.NET было внесено несколько небольших улучшений, таких как возможность подписаться на события удаления, не обязательно присутствуя при добавлении элементов, была удалена избыточная Insert (), элементы можно добавлять с помощью CacheItem объект с инициализатором, определяющим стратегию кеширования, и был добавлен Contains ().

Минусы:

  1. Все еще не полностью усиливает DRY. Судя по моему небольшому опыту, вы все еще не можете установить скользящий срок действия TimeSpan один раз и забыть об этом. И, честно говоря, хотя политика в приведенном выше примере добавления элементов более читабельна, она требует ужасающей многословности.
  2. Он все еще не имеет общих ключей; в качестве ключа требуется строка. Таким образом, вы не можете хранить столько же long или int, если вы кешируете записи данных, если не конвертируете в строку.

Сделай сам: собери сам

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

  1. Создайте класс контейнера значений, называемый чем-то вроде Expiring или Expired, который будет содержать значение типа T, свойство TimeStamp типа DateTime для хранения, когда значение было добавлено в кеш, и TimeSpan, который будет указывать, насколько далеко от отметки времени, которая срок действия предмета должен истечь. Для явного истечения срока вы можете просто предоставить средство установки свойств, которое устанавливает TimeSpan с учетом даты, вычтенной из метки времени.
  2. Создайте класс, назовем его ExpiredItemsDictionary, который реализует IDictionary. Я предпочитаю сделать его универсальным классом, определяемым потребителем.
  3. В классе, созданном в # 2, добавьте Dictionary> в качестве свойства и назовите его InnerDictionary.
  4. Реализация, если IDictionary в классе, созданном в # 2, должна использовать InnerDictionary для хранения кешированных элементов. Инкапсуляция скроет детали метода кеширования через экземпляры типа, созданного в # 1 выше.
  5. Убедитесь, что индексатор (this []), ContainsKey () и т. Д. Тщательно очищает просроченные элементы и удаляет просроченные элементы перед возвратом значения. Возвращает null в геттерах, если элемент был удален.
  6. Используйте блокировки потоков для всех методов получения, установки, ContainsKey () и особенно при очистке просроченных элементов.
  7. Создавать событие всякий раз, когда элемент удаляется из-за истечения срока его действия.
  8. Добавьте экземпляр System.Threading.Timer и настройте его во время инициализации для автоматического удаления просроченных элементов каждые 15 секунд. Это то же поведение, что и кеш ASP.NET.
  9. Вы можете добавить подпрограмму AddOrUpdate (), которая выталкивает скользящее истечение срока, заменяя временную метку в контейнере элемента (истекающий экземпляр), если он уже существует.

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

Плюсы:

  1. У вас есть полный контроль над реализацией.
  2. Можно усилить DRY , настроив поведение кэширования по умолчанию, а затем просто отбрасывая пары ключ / значение без объявления деталей кеширования каждый раз, когда вы добавляете элемент.
  3. Можно реализовать современные интерфейсы , а именно IDictionary<K,T>. Это значительно упрощает использование, поскольку его интерфейс более предсказуем, чем интерфейс словаря, а также делает его более доступным для помощников и методов расширения, которые работают с IDictionary <>.
  4. Детали кеширования могут быть неинкапсулированными , например, путем раскрытия вашего InnerDictionary через общедоступное свойство, доступное только для чтения, что позволяет вам писать явные модульные тесты на соответствие вашей стратегии кэширования, а также расширять вашу базовую реализацию кэширования дополнительными стратегиями кэширования, которые основаны на нем.
  5. Хотя это не обязательно знакомый интерфейс для тех, кто уже освоился с синтаксисом стиля .NET 1.0 для кэша ASP.NET или блока кэширующего приложения, вы можете определить интерфейс так, чтобы он выглядел так, как вы хотите.
  6. Можно использовать любой тип ключей. Это одна из причин, почему были созданы дженерики. Не все должно быть привязано к строке.

Минусы:

  1. Не является изобретением и не одобрено Microsoft , поэтому у него не будет такой же гарантии качества.
  2. Предполагая, что реализованы только инструкции, описанные мною выше, не происходит «волей-неволей» очистки элементов для очистки памяти на основе приоритета (что в любом случае является служебной функцией кеша). ПОКУПКА ОЗУ там, где вы бы использовали кеш , Оперативка дешевая).

Среди всех четырех вариантов я предпочитаю именно этот. Я реализовал это базовое решение для кеширования. Пока что, похоже, он работает идеально, нет известных ошибок (пожалуйста, свяжитесь со мной с комментариями ниже или в jon-at-jondavis, если они есть !!), и я намерен использовать его во всех своих небольших побочных проектах, которые нуждаются в базовое кеширование. Вот:

Ссылка на Github: https://github.com/kroimon/ExpirableItemDictionary

Старая ссылка: ExpiredItemDictionary.zip

Стоит упомянуть: AppFabric, NoSQL и др.

Обратите внимание, что в заголовке этой статьи блога указано «Простое кэширование», а не «Сверхмощное кэширование». Если вы хотите заняться тяжелыми задачами, вам следует обратить внимание на специальные масштабируемые решения.

DeepSpace101
источник
3

MemoryCache - это то, что он говорит, кеш, хранящийся в памяти

HttpRuntime.Cache (см http://msdn.microsoft.com/en-us/library/system.web.httpruntime.cache(v=vs.100).aspx и http://msdn.microsoft.com/en- us / library / system.web.caching.cache.aspx ) сохраняется в зависимости от того, что вы настроили в своем приложении.

см., например, «ASP.NET 4.0: Написание настраиваемых поставщиков кэша вывода» http://weblogs.asp.net/gunnarpeipman/archive/2009/11/19/asp-net-4-0-writing-custom-output-cache -providers.aspx

Кристиан Вестман
источник
1
Хм, не уверен, не вводит ли вторая ссылка в заблуждение, потому что идет речь о OutputCache и реализации OutputCacheProvider.
Giedrius
Хм, я не могу найти, где было бы сказано, что вы можете сохранить System.Web.Caching.Cache, используя другую конфигурацию
Гедриус
2

MemoryCache.Default также может служить «мостом», если вы переносите классическое приложение ASP.NET MVC в ASP.NET Core, поскольку в Core нет «System.Web.Caching» и «HttpRuntime».

Я также написал небольшой тест для хранения boolэлемента 20000 раз (и еще один тест для его извлечения), и MemoryCache кажется в два раза медленнее (27 мс против 13 мс - всего для всех 20 тысяч итераций), но они оба сверхбыстрые, и это вероятно, можно проигнорировать.

Alex
источник