Не удаляются файлы кэш (assets/cache/)
Доброго времени суток!
Столкнулся проблемой — не удаляются файлы кэш (assets/cache/).
При нажатии кнопки «Очистить кэш» система сообщает:
При этом, на самом деле этого не делает, т.е. по адресу «assets/cache/» всё ещё присутствуют файлы типа «docid_XX.pageCache.php».
Сейчас приходится вручную удалять всё по FTP, что весьма уже утомляет.
Что уже делал:
1) Перепроверил доступ к папке «assets/cache/» и содержащимся в ней файлы — 777;
2) Пробовал перезаливать и вновь устанавливать систему MODx скаченную с официального сайта;
3) Путь к файлам и файл-менеджера сбрасывал, всё тщетно… т.е. файл-менеджер работает (заливает файлы как и положено).
Произошло это после обновления MODx Evo с 1.0.10 на 1.0.12. На старой версии, так что 1.0.10, кэш нормально очищался.
Буду очень признателен за советы в решении проблемы.
P.S. Хостинг работает на ОС Debian GNU/Linux и панелью управления Parallels Plesk Panel
Комментарии (5)
Я бы порекомендовал поэкспериментировать на другом хосте, используя тот же самый сайт. Но, конечно, стоит в первую очередь проверять логи сервера, там скорее всего будут ответы на Ваши вопросы.
Прежде всего, спасибо за внимание! Однако к большому сожалению сменить хостинг не представляется возможным. Жаль, что эта досадная неприятность замечена не сразу после обновления, а уже после добавления достаточного количества ресурсов, а так бы откатил на 1.0.10 🙁
Кстати, вот что пишется в разделе «Системная информация»:
Пути же правильно вроде выставлены?
Запустите сайт на локалке если сможете и посмотрите удаляются файлы или нет. Может дело в каком-то функционале накрученном (плагины там например какие-нибудь), который оказался несовместим с обновлением.
Логи тоже надо обязательно посмотреть + настроить уровень вывода ошибок PHP чтобы в логи все ошибки падали
Ерунда какая-то… 🙁
Зашёл в «Управление файлами» пишет:
Т.е. файловый менеджер не видет содержимого, хотя имеет права за запись.
Для добавления комментариев вы должны авторизоваться или зарегистрироваться.
Особенности кэширования компонентов в Unity3D
Большинство unity-разработчиков знают, что не стоит злоупотреблять дорогими для производительности операциями, такими как, например, получение компонентов. Для этого стоит использовать кэширование. Но и для такой простой оптимизации можно найти несколько различных подходов.
В этой статье будут рассмотрены разные варианты кэширования, их неочевидные особенности и производительность.
Стоит отметить, что говорить мы будем в основном о “внутреннем” кэшировании, то есть получении тех компонентов, которые есть на текущем объекте для его внутренних нужд. Для начала откажемся от прямого назначения зависимостей в инспекторе — это неудобно в использовании, засоряет настройки скрипта и может привести к битым ссылкам при вылете редактора. Поэтому будем использовать GetComponent().
В Unity3D каждый объект на игровой сцене — это контейнер (GameObject) для различных компонентов (Component), которые могут быть как встроенными в движок (Transform, AudioSource и т.д.), так и пользовательскими скриптами (MonoBehaviour).
Компонент может быть назначен напрямую в редакторе, а для получения компонента из контейнера в скрипте используется метод GetComponent().
Если компонент требуется использовать не единожды, традиционный подход — объявить в скрипте, где он будет использоваться, переменную для него, взять нужный компонент один раз и в дальнейшем использовать полученное значение. Пример:
Стоит отметить, что самый очевидный метод кэширования (прямое получение компонентов) изначально является наиболее производительным в общем случае и другие варианты лишь его используют и предоставляют более простой доступ к компонентам, избавляя от необходимости писать однотипный код каждый раз либо получать компоненты по запросу.
Также отмечу, что есть и намного более дорогие операции (такие как создание и удаление объектов на сцене) и кэшировать компоненты, не уделяя внимания им, будет пустой тратой времени. Например, в вашей игре есть пулемет, который стреляет пулями, каждая из которых является отдельным объектом (что само по себе неправильно, но это же сферический пример). Вы создаете объект, кэшируете в нем Collider, ParticleSystem и еще кучу всего, но пуля улетает в небо и убивается через 3 секунды, а эти компоненты не используются вообще.
Для того, чтобы этого избежать, используйте пул объектов, об этом есть статьи на Хабре (1, 2) и существуют готовые решения. В таком случае вы не будете постоянно создавать и удалять объекты и раз за разом кэшировать их, они будут переиспользоваться, а кэширование произойдет лишь единожды.
Производительность всех рассмотренных вариантов кэширования будет отображена в сводной диаграмме.
Основы
У метода GetComponent есть два варианта использования: шаблонный GetComponent() и обычный GetComponent(type), требующий дополнительного приведения (comp as T). В сводной диаграмме по производительности будут рассмотрены оба этих варианта, но стоит учесть, что шаблонный метод проще в применении. Также существует вариант получения списка компонентов GetComponents с аналогичными вариантами, они также будут проверены. В диаграммах время выполнения GetComponent на каждой платформе принято за 100% для нивелирования особенностей оборудования, а также есть интерактивные версии для большего удобства.
Использование свойств
Для кэширования можно использовать свойства. Плюс этого метода — кэширование произойдет только тогда, когда мы обратимся к свойству, и его не будет тогда, когда это свойство используется. Минус заключается в том, что в данном случае мы пишем больше однотипного кода.
Самый простой вариант:
Этот вариант благодаря проверке на отсутствие компонента обладает проблемами с производительностью.
Есть два варианта решения этой проблемы:
Использовать дополнительный флаг, указывающий, производилось ли кэширование:
Явно приводить компонент к object:
Но нужно учитывать, что этот вариант безопасен только в том случае, когда компоненты объекта не удаляются (что обычно происходит нечасто).
When you get a c# object of type “GameObject”, it contains almost nothing. this is because Unity is a C/C++ engine. All the actual information about this GameObject (its name, the list of components it has, its HideFlags, etc) lives in the c++ side. The only thing that the c# object has is a pointer to the native object. We call these c# objects “wrapper objects”. The lifetime of these c++ objects like GameObject and everything else that derives from UnityEngine.Object is explicitly managed. These objects get destroyed when you load a new scene. Or when you call Object.Destroy(myObject); on them. Lifetime of c# objects gets managed the c# way, with a garbage collector. This means that it’s possible to have a c# wrapper object that still exists, that wraps a c++ object that has already been destroyed. If you compare this object to null, our custom == operator will return “true” in this case, even though the actual c# variable is in reality not really null.
Проблема здесь в том, что приведение к object хоть и позволяет обойти дорогой вызов native-кода, но при этом лишает нас кастомного оператора проверки существования объекта. Его C# обертка все еще может существовать, когда на самом деле объект уже уничтожен.
Наследование
Для упрощения задачи можно наследовать свои классы от компонента, кэширующего самые используемые свойства, но этот вариант неуниверсален (требует создания и модификации всех необходимых свойств) и не позволяет наследоваться от других компонентов, если это потребуется (в C# нет множественного наследования).
Первая проблема может быть решена использованием шаблонов:
Вторую проблему можно обойти, создав отдельный компонент для кэширования и используя в своих скриптах ссылку на него.
Статическое кэширование
Есть вариант использования такой особенности C#, как расширение. Она позволяет добавлять свои методы в уже существующие классы без их модификации и наследования. Это делается следующим образом:
После этого в любом скрипте можно получить этот компонент:
Но этот вариант снова требует задания всех необходимых компонентов заранее. Можно решить это с помощью шаблонов:
Минус этих вариантов — нужно следить за мертвыми ссылками. Если не очищать кэш (например, при загрузке сцены), то его объем будет только расти и засорять память ссылками на уже уничтоженные объекты.
Сравнение производительности
Интерактивный вариант
Как мы видим, серебряной пули не нашлось и самый оптимальный вариант кэширования — получать компоненты напрямую при инициализации. Обходные пути не оптимальны, за исключением свойств, которые требуют написания дополнительного кода.
Использование атрибутов
Атрибуты позволяют добавлять мета-информацию для элементов кода, таких как, например, члены класса. Сами по себе атрибуты не выполняются, их необходимо использовать при помощи рефлексии, которая является достаточно дорогой операцией.
Мы можем объявить свой собственный атрибут для кэширования:
И использовать его для полей своих классов:
Но пока что это нам ничего не даст, данная информация никак не используется.
Наследование
Мы можем создать свой класс, который будет получать члены класса с данным атрибутом и явно получать их при инициализации:
Если мы создадим наследника этого компонента, то сможем помечать его члены атрибутом [Cached], тем самым не заботясь о их явном кэшировании.
Но проблема с производительностью и необходимость наследования нивелирует удобство данного метода.
Статический кэш типов
Список членов класса не меняется при выполнении кода, поэтому мы можем получить его один раз, сохранить его для данного типа и использовать в дальнейшем, почти не прибегая к дорогой рефлексии. Для этого нам потребуется статический класс, хранящий результаты анализа типов.
И теперь для кэширования в каком-либо скрипте мы используем обращение к нему:
После этого все члены класса, помеченные [Cached] будут получены с помощью GetComponent.
Эффективность кэширования с помощью аттрибутов
Сравним производительность для вариантов с 1 или 5 кэшируемыми компонентами:
Интерактивный вариант
Интерактивный вариант
Шаг назад или использование редактора
Уже когда я заканчивал эту статью, мне подсказали одно интересное решение для кэширования. Так ли необходимо в нашем случае сохранять компоненты именно в запущенном состоянии приложения? Вовсе нет, мы это делаем только единожды для каждого экземпляра, соответственно функционально это ничем не отличается от назначения их в редакторе до запуска приложения. А все, что можно сделать в редакторе, можно автоматизировать.
Так появилась идея кэшировать зависимости скриптов с помощью отдельной опции в меню, которая подготавливает экземпляры на сцене к дальнейшему использованию.
Вполне возможно, что текущие ограничения в дальнейшем можно будет устранить.
Особенности получения отсутствующих компонентов
Интересной особенностью оказалось то, что попытка получить отсутствующий компонент занимает больше времени, чем получение существующего. При этом в редакторе наблюдается заметная аномалия, которая и навела на мысль проверить это поведение. Так что никогда не полагайтесь на результаты профилирования в редакторе.
Интерактивный вариант
Заключение
В данной статье вы увидели оценку различных методов кэширования компонентов, а также узнали об одном из полезных применений атрибутов. Методы, основанные на рефлексии, в принципе, могут применяться при создании проектов на Unity3D, если учитывать его особенности. Один из них позволяет писать меньше однотипного кода, но чуть менее производителен, чем решение “в лоб”. Второй на данный момент требует чуть больше внимания, но не влияет на итоговую производительность.
Проект с исходниками скриптов для теста и proof-of-concept кэша с помощью атрибутов доступны на GitHub (отдельный пакет с итоговой версией здесь). Возможно, у вас найдутся предложения по улучшению.
Спасибо за внимание, надеюсь на полезные комментарии. Наверняка этот вопрос рассматривался многими и вам есть что сказать по этому поводу.
Как, почему и когда надо чистить кэш на Android
Кэш приложений может быть спорной темой на Android. Многие люди постоянно чистят кэш приложений, веря в то, что это позволит смартфону работать быстрей. Другие говорят, что это, в первую очередь, сводит на нет всю цель кэширования и просто увеличивает время запуска приложений и выполняемых действий. Истина, как обычно, где-то посередине. Некоторые приложения могут не использовать кэширование эффективно, из-за чего используются излишне большие объемы памяти. Иногда кэш может вызывать проблемы после выхода обновления и надо его сбрасывать. А еще некоторые приложения могут начинать работать медленнее, когда их кэш становится очень большим. Сказать однозначно, надо ли его удалять, нельзя. Но сейчас рассмотрим эту тему подробнее, чтобы вы понимали, когда это делать и как?
Надо ли чистить кэш телефона?
Что такое кэш на Андройд
Кэширование в компьютерном мире это то, что позволяет приложениям, таким, как браузеры, игры и потоковые сервисы хранить временные файлы, которые считаются актуальными для уменьшения времени загрузки и увеличения скорости работы. YouTube, Карты, музыкальные сервисы и множество других приложений сохраняют информацию в виде данных кэша. Это могут быть миниатюры видео, история поиска или временно сохраненные фрагменты видео. Кэширование может сэкономить много времени, так как качество и скорость Интернета не везде одинаковы. Но по иронии судьбы, когда приложения выгружают много данных на ваш телефон, это в конечном итоге замедляет его работу, особенно, когда остается мало места на встроенной памяти.
Наш Иван Кузнецов не так давно писал о том, что никогда не чистит кэш и считает это не нужным. Многие из вас, возможно, с ним не согласны. Да я и сам переодически провожу эту процедуру. Тем не менее, для полноты картины можете ознакомиться с его мнением.
Очистка кэша и данных на Android
Хотя мы часто упоминаем очистку кэша и данных в одном ключе, на Android это два совершенно разных действия. Например, музыкальные сервисы часто сохраняют в кэш информацию, относящуюся к исполнителям, которых вы слушали, но которые не входят в вашу библиотеку. Когда кэш приложения очищается, все упомянутые данные стираются.
Очистка лишней не будет? Не факт.
Более существенные данные включают в себя пользовательские настройки, базы данных и данные для входа в систему. Когда вы очистите кэш, это все удалится и будет не очень приятно. Если говорить грубо, можно сказать, что очистка кэша придает приложению тот вид, который был сразу после его установки, но у вас останутся данные, которые вы сами осознанно сохранили (загруженные песни, видео в оффлайн, карты и так далее). Если вы удалите и эти данные, то приложение будет вообще нулевым. Если чистите и кэш, и данные, проще тогда и приложение переустановить, чтобы вообще все красиво было.
Как очистить память смартфона. Пять простых шагов.
Когда надо чистить кэш
В чем-то я согласен с Иваном и с его мнением, которое я приводил в начале статьи. Нет смысла чистить кэш часто. После того, как вы его очистили, приложение все равно его создаст заново. Только в это время оно будет работать еще медленнее.
Тут важно найти баланс и понять, действительно ли ваш смартфон тормозит из-за кэша или, например, он просто старый и уже не тянет. Если не вникать в это, то можно посоветовать чистить кэш один раз в 3-6 месяцев, но быть готовым, что первые несколько дней скорость работы будет чуть ниже. В итоге, вы как бы освежите приложение, удалив лишний мусор и заново собрав только то, что нужно.
Google Play рассылает пустые обновления приложений. Что делать?
Как очистить кэш и данные на Android
Точную инструкцию для каждого смартфона дать не получится, так как все зависит от производителя и версии ОС, но общие правила будут следующими.
Шаг 1: Запустите «Настройки» и перейдите в раздел «Хранилище» (или найдите его поиском). Так вы сможете узнать, сколько памяти вашего смартфона занято и чем.
Шаг 2. В разделе «Хранилище» найдите «Приложения» (или «Другие приложения») и выберите его. В нем будут перечислены все приложения, а также то, сколько места каждое из них занимает. В некоторых версиях ОС можно найти сортировку приложений по алфавиту или размеру.
Шаг 3: Зайдите внутрь приложения и удалите кэш или данные. Только надо понимать, что это действие необратимо.
Три простых шага для очистки кэша.
В отношении специальных приложений для очистки я очень категоричен и не рекомендую ими пользоваться. Несмотря на их обещания ускорить систему чуть ли не в разы, в лучшем случае они просто сделают то же, что я только что описал. Так почему бы не сделать это самому без установки сомнительных приложений, которые еще и будут собирать ваши данные? Единственное приложение-оптимизатор, которому я доверяю, это Google Файлы, но работает оно именно с хранилищем и чистит в первую очередь мусор. Хотя, на него тоже нельзя слепо полагаться, но оно сделано Google, а к ней доверия куда больше, чем к каким-то левым разработчикам.
Если вы все еще хотите установить подобное приложение, просто помните о том, что они работают в фоновом режиме и используют системные ресурсы. Даже если они что-то ускорят, то сразу замедлят обратно.
Надо ли чистить кэш Android-приложений
Возможность очистки данных — это действительно полезная функция для решения многих проблем, уникальная для Android. Но как и любой полезной вещью злоупотреблять ей не стоит. Не надо чистить кэш и память каждый день. Делайте это периодически и только по мере надобности. Начал телефон работать медленно — пробегитесь по хранилищу. Если увидели, что какое-то из приложений занимает слишком много места, хотя не должно, очистите кэш.
Еще больше полезных советов и рассуждения в нашем Telegram-канале.
Еще раз: очистка кэша не испортит ваш смартфон, но приложение потеряет часть сохраненных данных и оптимизированных под вас настроек. Некоторое время придется накапливать их заново, зато так можно убрать действительно лишнее. Раньше можно было одной кнопкой очистить кэш всех приложений, теперь только по одному, но, наверное, это к лучшему.
Чего точно не стоит делать с кэшем, так это чистить его каждый день или каждую неделю. Так вы точно не сделаете лучше никому.
Что такое кэш и зачем его чистить
Это старые данные, которые уже могут быть неактуальны
Когда не работает какой-то сайт или сервис, от техподдержки часто можно услышать «Почистите кэш и перезагрузите страницу». Иногда это помогает. Рассказываем, почему так происходит, что такое кэш, зачем он нужен и как его почистить.
⚠️ Минутка грамотности. По словарю РАН слово cache в русском пишется «кеш». Но по рекомендациям Гиляревского нужно писать «кэш». И нам нравится, как это произносится. Произнесите вместе с нами:
Что такое кэш
Кэш — это данные, которые компьютер уже получил и использовал один раз, а потом сохранил на будущее. Смысл кэша в том, чтобы в следующий раз взять данные не с далёкого и медленного сервера, а из собственного быстрого кэша. То же самое, что закупиться продуктами на неделю и потом ходить не в магазин, а в холодильник.
В случае с браузером это работает так:
Дальше происходит так:
4. Если вкладкой или браузером долго не пользовались, операционная система выгружает из оперативной памяти все страницы, чтобы освободить место для других программ.
5. Если переключиться назад на браузер, он моментально сходит в кэш, возьмёт оттуда загруженную страницу и покажет её на экране.
Получается, что если браузер будет брать из кэша только постоянные данные и скачивать с сервера только что-то новое, то страница будет загружаться гораздо быстрее. Выходит, главная задача браузера — понять, какой «срок годности» у данных в кэше и через какое время их надо запрашивать заново.
👉 Например, браузер может догадаться, что большая картинка на странице вряд ли будем меняться каждые несколько секунд, поэтому имеет смысл подержать её в кэше и не загружать с сервера при каждом посещении. Поэтому в кэше часто хранятся картинки, видеоролики, звуки и другие декоративные элементы страницы.
👉 Для сравнения: браузер понимает, что ответ сервера на конкретный запрос пользователя кэшировать не надо — ведь ответы могут очень быстро меняться. Поэтому ответы от сервера браузер не кэширует.
Какая проблема с кэшем
На первый взгляд кажется, что кэш — это прекрасно: данные уже загружены, к ним можно быстро обратиться и достать оттуда всё, что нужно, без запроса к серверу на другом конце планеты.
Но представьте такую ситуацию: вы заходите в интернет-магазин обуви, в котором покупали уже много раз, но товары почему-то не добавляются в корзину. Или добавляются, но кнопка «Оплатить» не работает. Чаще всего причина в том, что браузер делает так:
Решение — почистить кэш
Когда мы чистим кэш, оттуда удаляются все данные, которые браузер сохранил «на всякий случай». Это значит, что при обновлении страницы браузер заглянет в кэш, увидит, что там пусто и запросит все данные с сервера заново. Они, конечно, тоже сразу отправятся в кэш, но в следующий раз вы уже будете знать, что делать.
Чтобы очистить кэш в Сафари, достаточно нажать ⌥+⌘+E, а в Хроме — нажать Ctrl+Shift+Backspace (⇧+⌘+Backspace) и выбрать время, в пределах которого нужно очистить кэш:
Зачем нужен кэш, если из-за него всё ломается?
На самом деле всё ломается не из-за кэша, а из-за неправильных настроек сервера, которые отдают страницу. Потому что именно сервер должен сказать браузеру: «Вот это можно кэшировать, а вон то лучше не кэшируй, мало ли что».
Часто разработчики недокручивают эти настройки, и браузер не получает нужных инструкций, поэтому кэширует всё подряд. И тогда приходится вмешиваться, чистить кэш и восстанавливать работоспособность.
Что нам стоит Cache построить?
Написано не мало хороших статей на тему «Что, как и где кешировать». Так почему же ещё раз мусолить эту тему? А потому что тема достаточно важная, а многие, пока не столкнуться с конкретными проблемами, не считают нужным с ней разбираться. Так что аудитория, на которую я рассчитываю, это те, кто к моменту выхода уже существующих статей были в них не заинтересованы, но сейчас интерес есть, и они не пройдут мимо.
Вступление
Что? Как? Где?
Когда мы решаем, что мы будем кешировать, нужно понимать, что кеш не бесплатный и будет полезен далеко не для всех типов данных. Независимо от выбранной стратегии кеширования и реализации кеша, у нас так или иначе будут проявляться проблемы устаревания данных и занимаемого ими объёма памяти. А в виду того, что кеширование добавляет сложность во время создания /тестирования/сопровождения нашего приложения, то однозначно не нужно кешировать всё подряд. Нужно взвешенно подходить к выбору тех мест, где добавление кеша кроме проблем принесёт ещё и выгоду.
Не стоит кешировать данные, которые полезны только в режиме реального времени. Например, котировки валют в трейдерской системе, устаревшие на 30 секунд, могут весомо повлиять на правильность принимаемых решений. Но если у нас в системе на домашней странице есть сводная статистика по продажам компании за последнюю неделю, то эти данные отлично подойдут для кеширования.
Также нет смысла кешировать то, что можно и так быстро получить из источника данных или высчитать на лету. Но если источник данных находится далеко и очень медленный, а специфика данных позволяет их использовать с какой-то задержкой, то это хорошие кандидаты для кеширования.
В качестве другого примера, давайте рассмотрим данные, которые рассчитываются на лету, требуют много процессорного времени, но полученный результат достаточно большой по объёму. При попытке кеширования этих данных, мы очень быстро можем заполнить всю доступную память, поместив в неё всего лишь несколько результатов. В этих условиях будет сложно добиться эффективной работы кеша, т.к. велика вероятность, что буквально несколько новых элементов будут приводить к затиранию только что рассчитанных значений и процент успешных попаданий (нахождение нужного элемента в кеше) будет крайне низкий. В этом случае нужно скорее задумываться над ускорением алгоритма расчёта, нежели о кешировании результата. Выбирая правильных кандидатов для сохранения в кеш, всегда думайте об эффективности кеша. Т.е. мы должны стремиться к тому, чтобы выбранные нами данные, будучи помещёнными в кеш, извлекались из него многократно до того, как они будут из него вытолкнуты более новыми данными или станут устаревшими.
Итак, получив ответы на вопросы «Что» и «Как», может оказаться, что нашим ответом на вопрос где будет Dictionary созданный в нашем приложении. Если так, то нам очень повезло. Но, как правило, всё чуточку сложнее и нам всё-таки придётся писать полноценную реализацию кеша либо выбирать что-то из уже готовых решений.
Примечание: нет единого мнения касательно того, будет ли реализация на основе Dictionary считаться кешем или нет. Лично я предпочитаю считать это частным случаем, который обособленно «стоит в сторонке». При этом мне даже встречался термин описывающий такой кеш как «статический», т.е. кеш в котором данные не удаляются и считаются бесконечно актуальными.
Рукописный кеш
Я не стану рассказывать, как написать свой кеш. Я, наоборот, постараюсь уберечь вас от ложного впечатления, что это сделать легко и просто. За исключением случая, когда Dictionary-like реализация отлично покрывает наши потребности, написание полноценного кеша является достаточно сложной задачей.
Первая сложность, которая приходит в голову – это работа в многопоточном окружении. Ведь если мы используем кеш, то наверняка система не маленькая и работать в одном потоке будет крайне неэффективно. Т.е. все операции записи/чтения/инвалидации данных должны быть потоко-безопасны. Без обширного опыта работы с потоками, нам гарантированы взаимоблокировки или медленная работа из-за не оптимально выбранного подхода синхронизации потоков.
Если подумать о том, как происходит устаревание данных, то в голову может прийти ряд далеко не самых простых сценариев, которые должен поддерживать наш кеш. Взяв декартовое произведение всех возможных вариантов, мы получим то множество состояний, в которых сможет оказаться наша система. Это станет достаточным основанием, чтобы сделать задачу отладки и тестирования самописного кеша просто неподъёмной.
Многие примеры, реализующие кеширование, которые можно найти в интернете, используют механизм слабых ссылок (Weak references). Может появиться неудержимое желание применить их в своей реализации. Но без достаточного опыта в соответствующей области, мы не слабо увеличиваем шансы получить код, который мало того, что большинство команды не будет понимать, так он ещё навряд ли заработает после первых 5 раз переписывания.
Я думаю, что мог бы ещё долго продолжать этот список, но надеюсь, что даже уже перечисленных причин достаточно, чтобы у вас пропало желание проверять себя на прочность и усидчивость. Если же нет, то я могу лишь пожелать «Силы, ума и терпения (С)».
ObjectCache
ObjectCache — абстрактный класс, который даёт нам возможность стандартизировать подходы при работе с различными реализациями кеша. Имея одинаковый интерфейс (API) для работы с кешом, нам не придётся детально изучать каждую новую реализацию кеша. Ведь реализации с точки зрения пользователя должны будут выглядеть одинаково и вести себя согласно общеизвестным ожиданиями, выраженными в виде API данного класса. Основные методы, свойства и их назначение приведены ниже.
MemoryCache
Метод AddOrGetExisting(…)
Добавляет элемент, только в случае, если ключ ещё не был использован, иначе игнорирует новое значение и возвращает существующее значение.
Метод Add(…)
Является обвёрткой над AddOrGetExisting(…) и работает практически идентично, с тем лишь различием, что он возвращает True, если элемент успешно добавлен, и False, если ключ уже существует (т.е. добавление значения не происходит).
Метод Set(…)
Добавляет новый или замещает существующий элемент, не производя проверку существующих ключей. Т.е. в отличии от методов Add и AddOrGetExisting, переданное значение в метод Set всегда появится в кеше.
Регионы в MemoryCache
Все методы добавления данных в MemoryCache имеют перегрузки, которые принимают параметр region (пример1, пример2 и пример3). Но при попытке передать в него любое не NULL значение мы получим NotSupportedException. Кто-то может сказать, что это нарушает принцип подстановки Лисков (soLid), но это не так. Ведь прежде чем воспользоваться возможностью регионов, клиентский код должен убедится, что они реализованы в конкретной реализации. Делается это проверкой свойства DefaultCacheCapabilities на наличие соответствующего битового флага (DefaultCacheCapabilities.CacheRegions), а он как раз не задан для MemoryCache.
CacheItemPolicy
Для демонстрации всех методов добавления данных были выбраны наиболее простые версии перегрузок, принимающие ключ, значение и время, до которого значение будет считаться актуальным. Но все они так же имеют версию, которая принимает параметр типа CacheItemPolicy. Именно благодаря этому параметру у нас есть достаточно богатые возможности по управлению временем жизни элемента в кеше, что делает реализацию MemoryCache крайне полезной.
Большинство свойств данного типа выглядят понятно, но на практике мы столкнёмся с множеством неожиданных сюрпризов. Строго говоря, многие из них будут не в самом классе CacheItemPolicy, а в логике методов MemoryCache, которые принимают этот тип. Но так как используются эти типы часто вместе, то предлагаю их рассмотреть тоже вместе.
Свойства AbsoluteExpiration и SlidingExpiration
Из названия понятно за что отвечают эти свойства. Но любопытные могут задаться следующим вопросом: «Как себя поведёт кеш, если одновременно задать значения для обоих свойств»? Кто-то может предположить, что AbsoluteExpiration имеет более высокий приоритет и объект удалится в момент AbsoluteExpiration, даже если его регулярно запрашивать из кеша (чаще чем SlidingExpiration). Кто-то наоборот, предположит, что значение SlidingExpiration позволит объекту пережить AbsoluteExpiration. Но разработчики Микрософта, посчитали, что истинно правильного ответа нет и поступили по-другому – они генерируют ArgumentException на этапе добавления элемента в кеш. Поэтому мы можем выбрать только одну временнУю (зависящую от времени) стратегию инвалидации для каждого элемента.
Второй сюрприз нас ожидает, если мы решим написать тесты на функционал, использующий кеш. Наверняка, для ускорения прогона тестов, мы захотим задать достаточно маленькое значение для SlidingExpiration (менее 1 секунды). В этом случае наши тесты будут вести себя не стабильно и часто будут падать. Это всё по тому, что для оптимизации работы кеша, в момент вычитывания элемента (метод Get и его производные), новое значение Expires будет устанавливаться только, если оно отличается от старого, не менее чем на одну секунду. Я не смог найти подтверждение этому в документации, но убедиться в этом можно декомпилировав класс MemoryCache и изучив метод UpdateSlidingExp(…) внутреннего класса MemoryCacheEntry.
Свойство Priority
Увидев это свойство, я ожидал, что оно может иметь значения «низкий/средний/высокий», чтобы задать порядок удаления элементов из кеша при достижении максимального объёма. Но у него может быть только 2 значения: CacheItemPriority.Default или CacheItemPriority.NotRemovable.
MSDN гласит, что установка значения CacheItemPriority.NotRemovable приведёт к тому, что элемент никогда не будет удалён из кеша. Лично я воспринял этот факт, как то, что, добавив все элементы с таким приоритетом, мы получим Dictionary-like реализацию, но это далеко не так. Элементы всё же будут удалены, если они «протухнут» (наступит AbsoluteExpiration или пройдет SlidingExpiration), но в отличии от режима по умолчанию, они не будут удаляться из памяти, при достижении лимита по объёму занимаемой памяти. Кстати лимит можно задать через свойство CacheMemoryLimit (в байтах) или через свойство PhysicalMemoryLimit (проценты от общего объёма памяти в системе).
RemovedCallback и UpdateCallback
Очередной сюрприз. Оба свойства принимают делегаты, которые будут вызваны, как в случае обновления, так и в случае удаления элемента из кеша.
Если задуматься, то обновление, это по сути операция удаления, после которой сразу же следует операция добавления нового значения. Это объясняет, почему RemovedCallback срабатывает при обновлении элемента. А то что UpdateCallback срабатывает при удалении – просто факт из MSDN.
Различие же свойств заключается в том, что RemovedCallback должен вызываться после, а UpdateCallback – до фактического удаления элемента из кеша. Делегаты, хранимые в этих свойствах, принимают параметр, в котором содержится ссылка на кеш, ссылка на удаляемый элемент и причина удаления элемента.
Ещё один подарок хранится в реализации MemoryCache. В этом классе есть немного странная логика валидации переданного CacheItemPolicy параметра. Сначала она проверяет, что бы оба делегата не были заданы одновременно, иначе мы получим ArgumentException на этапе добавления элемента в кеш.
И всё бы ничего, если б для корректной работы свойства UpdateCallback было бы достаточно убедиться в отсутствии значения в свойстве RemovedCallback. Но по факту, мы всегда получаем ArgumentException на этапе добавления элемента при установке не пустого значения в UpdateCallback.
В итоге, единственно допустимое свойство для установки делегата сигнализирующего об изменениях в кеше является RemovedCallback (справедливо только для реализации MemoryCache).
Свойство ChangeMonitors
Данное свойство может хранить коллекцию объектов типа ChangeMonitor, каждый из которых может добавлять условия, при которых элемент будет удалён из кеша.











