Ось стаття Джона Девіса. Щоб зберегти читабельність, я вирізаю застарілий розділ EntLib, вступ, а також висновок.
Кеш ASP.NET
ASP.NET або збірка System.Web.dll має механізм кешування. Він ніколи не був призначений для використання поза веб-контекстом, але його можна використовувати і поза Інтернетом, і він виконує всі вищезазначені дії щодо закінчення терміну дії у своєрідних хеш-таблицях.
Після очищення Google виявляється, що чимало людей, які обговорювали вбудовану функціональність кешування в .NET, вдалися до використання кешу ASP.NET у своїх не-веб-проектах. Це вже не найдоступніша, найбільш підтримувана вбудована система кешування в .NET; .NET 4 має ObjectCache, який я розгляну пізніше. Корпорація Майкрософт завжди була категорична, що кеш ASP.NET не призначений для використання поза Інтернетом. Але багато людей все ще застрягли в .NET 2.0 та .NET 3.5, і їм потрібно щось працювати, і це трапляється для багатьох людей, хоча MSDN чітко говорить:
Примітка: Клас кеш-пам'яті не призначений для використання поза програмами ASP.NET. Він був розроблений і протестований для використання в ASP.NET для забезпечення кешування веб-додатків. В інших типах програм, таких як консольні програми або програми Windows Forms, кешування ASP.NET може працювати неправильно.
Класом кешу ASP.NET є System.Web.Caching.Cache в System.Web.dll. Однак ви не можете просто створити об'єкт кешу. Ви повинні придбати його в System.Web.HttpRuntime.Cache.
Cache cache = System.Web.HttpRuntime.Cache;
Робота з кешем ASP.NET задокументована тут на MSDN .
Плюси:
- Це вбудовано .
- Незважаючи на синтаксис .NET 1.0, ним досить просто користуватися.
- При використанні у веб-контексті він добре перевірений . За межами веб-контекстів, згідно з пошуковими запитами Google, загальновідомо, що це не спричиняє проблем, незважаючи на те, що Microsoft рекомендує проти цього, якщо ви використовуєте .NET 2.0 або пізнішу версію.
- Ви можете отримати сповіщення через делегата про вилучення предмета, що необхідно, якщо вам потрібно зберегти його в житті, і ви не можете встановити пріоритет товару заздалегідь.
- Окремі предмети мають гнучкість будь-якого із (а), (б) або (в) способів закінчення терміну дії та видалення у списку методів видалення у верхній частині цієї статті. Ви також можете пов’язати поведінку закінчення терміну дії із наявністю фізичного файлу.
Мінуси:
- Мало того, що він статичний, він є лише один . Ви не можете створити власний тип із власним статичним екземпляром кешу. Ви можете мати лише одне відро для всієї вашої програми, крапка. Ви можете обернути відро власними обгортками, які роблять такі речі, як префікси попереднього введення в ключі, і видаляти ці префікси, коли витягуєте пари ключ / значення назад. Але є ще лише одне відро. Все згруповано. Це може бути справжньою неприємністю, якщо, наприклад, у вас є служба, яка повинна кешувати три або чотири різні типи даних окремо. Це не повинно бути великою проблемою для пафосно простих проектів. Але якщо проект має якийсь значний ступінь складності через свої вимоги, кеш-пам'яті ASP.NET, як правило, буде недостатньо.
- Предмети можуть зникнути, волею-неволею. Багато людей цього не знають - я цього не знав, поки не оновив свої знання щодо реалізації цього кешу. За замовчуванням кеш-пам’ять ASP.NET призначена для знищення елементів, коли йому це здається. Більш конкретно, див. (C) у моєму визначенні кеш-таблиці у верхній частині цієї статті. Якщо інший потік у тому самому процесі працює над чимось зовсім іншим, і він скидає елементи високого пріоритету в кеш, то як тільки .NET вирішить, що йому потрібно трохи пам'яті, він почне знищувати деякі елементи в кеші відповідно до їх пріоритети, спочатку нижчі пріоритети. Усі приклади, задокументовані тут для додавання елементів кеш-пам'яті, використовують пріоритет за замовчуванням, а не значення пріоритету NotRemovable, яке не дає йому бути видаленим для очищення пам'яті, але все одно видалить його відповідно до політики закінчення терміну дії.
- Ключем повинен бути рядок. Якщо, наприклад, ви кешуєте записи даних, де записи вводяться на довге або ціле число, спочатку потрібно перетворити ключ у рядок.
- Синтаксис застарілий . Це синтаксис .NET 1.0, навіть потворніший, ніж ArrayList або Hashtable. Тут немає загальних препаратів, немає інтерфейсу IDictionary <>. У ньому немає методу Contains (), немає збору ключів, немає стандартних подій; він має лише метод Get () плюс індексатор, який робить те саме, що Get (), повертаючи нуль, якщо немає відповідності, плюс Add (), Insert () (надлишковий?), Remove () та GetEnumerator () .
- Ігнорує принцип СУХОГО встановлення типової поведінки закінчення терміну дії / видалення, щоб ви могли забути про них. Ви повинні чітко повідомляти кеш, як ви хочете, щоб термін дії, який ви додаєте, закінчився або був видалений кожного разу, коли ви додаєте, додаєте елемент.
- Немає доступу до деталей кешування кешованого елемента, наприклад позначки часу, коли він був доданий. Тут інкапсуляція трохи зашкалювала, ускладнивши використання кеш-пам’яті, коли в коді ви намагаєтесь визначити, чи слід кешувати елемент недійсним щодо іншого механізму кешування (тобто колекції сеансів) чи ні.
- Події видалення не виставляються як події, і їх слід відстежувати під час додавання.
- І якщо я цього недостатньо сказав, Microsoft прямо рекомендує забороняти це поза Інтернетом. І якщо ви прокляті .NET 1.1, ви не повинні використовувати його з будь-якою впевненістю в стабільності взагалі поза Інтернетом, тому не турбуйтеся.
ObjectCache / MemoryCache .NET 4.0
Нарешті, корпорація Майкрософт застосувала абстрактний клас 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)
});
Плюси:
- Він вбудований і тепер підтримується та рекомендується корпорацією Майкрософт поза Інтернетом.
На відміну від кешу ASP.NET, ви можете створити екземпляр екземпляра об’єкта MemoryCache.
Примітка: Він не повинен бути статичним, але повинен бути - це рекомендація корпорації Майкрософт (див. Жовте застереження) .
Було зроблено кілька незначних покращень щодо інтерфейсу кеш-пам'яті ASP.NET, таких як можливість підписатися на події видалення, не обов'язково перебуваючи там, коли елементи були додані, зайвий Insert () видалений, елементи можна додавати за допомогою CacheItem об'єкт з ініціалізатором, який визначає стратегію кешування, і додано Contains ().
Мінуси:
- Все ще не повністю підсилює СУХУ. З мого невеликого досвіду, ви все ще не можете встановити ковзний термін дії один раз і забути про це. І відверто кажучи, хоча політика у наведеному вище зразку додавання товару є більш читабельною, вона потребує жахливої багатослівності.
- Він все ще не є загальновстановленим; для цього потрібен рядок як ключ. Таким чином, ви не можете зберігати так довго або int, якщо ви кешуєте записи даних, якщо не перетворите їх на рядок.
Зроби сам: побудуй сам
Насправді досить просто створити словник кешування, який виконує явне або ковзне закінчення терміну дії. (Це стає набагато складніше, якщо ви хочете, щоб елементи автоматично видалялися з метою очищення пам'яті.) Ось усе, що вам потрібно зробити:
- Створіть клас контейнера значень, який називається щось на зразок Expiring або Expirable, який міститиме значення типу T, властивість TimeStamp типу DateTime, що зберігатиметься, коли значення було додано в кеш, і TimeSpan, який вказуватиме, як далеко від мітки часу, що термін дії товару повинен закінчитися. Для явного закінчення терміну дії можна просто виставити установку властивостей, яка встановлює TimeSpan, задану датою, віднятою від мітки часу.
- Створіть клас, назвемо його ExpirableItemsDictionary, який реалізує IDictionary. Я вважаю за краще зробити його загальним класом, визначеним споживачем.
- У класі, створеному в №2, додайте словник> як властивість і назвіть його InnerDictionary.
- Реалізація, якщо IDictionary у класі, створеному в # 2, повинна використовувати InnerDictionary для зберігання кешованих елементів. Інкапсуляція буде приховувати деталі методу кешування через екземпляри типу, створеного в No1 вище.
- Переконайтесь, що індексатор (this []), ContainsKey () тощо дбає про те, щоб очистити прострочені елементи та видалити прострочені елементи, перш ніж повертати значення. Повернути нуль у геттерах, якщо елемент було видалено.
- Використовуйте ниткові фіксатори на всіх геттерах, сеттерах, ContainsKey (), а особливо при очищенні елементів із закінченим терміном дії.
- Піднімайте подію щоразу, коли предмет вилучається через термін придатності.
- Додайте екземпляр System.Threading.Timer і встановіть його під час ініціалізації, щоб автоматично видаляти прострочені елементи кожні 15 секунд. Це така сама поведінка, як кеш ASP.NET.
- Можливо, ви захочете додати процедуру AddOrUpdate (), яка витісняє ковзне закінчення терміну дії, замінюючи позначку часу на контейнері елемента (закінчується екземпляр), якщо він уже існує.
Корпорація Майкрософт повинна підтримувати свої оригінальні конструкції, оскільки її користувацька база створила залежність від них, але це не означає, що вони хороші.
Плюси:
- Ви маєте повний контроль над реалізацією.
- Може підсилити DRY , налаштувавши поведінку кешування за замовчуванням, а потім просто опустивши пари ключ / значення, не оголошуючи деталі кешування кожного разу, коли ви додаєте елемент.
- Може реалізовувати сучасні інтерфейси , а саме
IDictionary<K,T>
. Це значно полегшує споживання, оскільки його інтерфейс є більш передбачуваним як інтерфейс словника, плюс це робить його більш доступним для помічників та методів розширення, які працюють з IDictionary <>.
- Деталі кешування можуть бути неінкапсульовані , наприклад, виставляючи ваш InnerD Dictionary через загальнодоступну властивість лише для читання, дозволяючи писати явні модульні тести проти вашої стратегії кешування, а також розширювати базову реалізацію кешування додатковими стратегіями кешування, які базуються на цьому.
- Незважаючи на те, що це не обов'язково звичний інтерфейс для тих, хто вже почував себе комфортно із синтаксисом стилю .NET 1.0 кеш-пам'яті ASP.NET або блоку кешування додатків, ви можете визначити інтерфейс таким, як ви хочете.
- Можна використовувати будь-який тип для ключів. Це одна з причин, чому були створені дженерики. Не все повинно бути введено рядком.
Мінуси:
- Не винайдена і не схвалена корпорацією Майкрософт , тому вона не матиме однакових гарантій якості.
- Якщо припустити, що реалізовані лише описані вище інструкції, це не “волею-неволею” очищає елементи для очищення пам’яті в пріоритеті (що в будь-якому випадку є утилітною функцією кешу в будь-якому випадку. , Оперативна пам'ять дешева).
Серед усіх чотирьох з цих варіантів це моя перевага. Я застосував це базове рішення кешування. Поки це, здається, працює чудово, немає відомих помилок (будь ласка, зв'яжіться зі мною з коментарями нижче або на jon-at-jondavis, якщо вони є !!), і я маю намір використовувати його у всіх своїх менших побічних проектах, які потребують основне кешування. Ось:
Посилання на Github: https://github.com/kroimon/ExpirableItemDictionary
Старе посилання: ExpirableItemDictionary.zip
Варто згадати: AppFabric, NoSQL та ін
Зверніть увагу, що в назві цієї статті в блозі вказується “Просте кешування”, а не “Кешування у важких режимах”. Якщо ви хочете зайнятися надміцними речами, вам слід поглянути на спеціальні, масштабовані рішення.