Потокобезопасные библиотеки кеша для .NET

Фон:

Я поддерживаю несколько приложений Winforms и библиотек классов, которые могут или уже могут извлечь выгоду из кэширования. Я также знаю оБлок приложения кеширования иSystem.Web.Caching namespace (которое, из того, что я собрал, совершенно нормально для использования вне ASP.NET).

Я обнаружил, что, хотя оба вышеперечисленных класса являются технически «поточно-ориентированными» в том смысле, что отдельные методы синхронизированы, на самом деле они не очень хорошо разработаны для многопоточных сценариев. В частности, они не реализуютGetOrAdd метод похож на тот, что в новомConcurrentDictionary класс в .NET 4.0.

Я считаю такой методпримитивный для функциональности кэширования / поиска, и, очевидно, разработчики Framework также поняли это - поэтому методы существуют в параллельных коллекциях. Однако, несмотря на то, что я еще не использую .NET 4.0 в производственных приложениях, словарь не является полноценным кешем - у него нет таких функций, как истечение срока хранения, постоянное / распределенное хранилище и т. Д.

Почему это важно:

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

Поэтому мне кажется, что у меня осталось несколько одинаково паршивых вариантов:

Не пытайтесь сделать операцию атомарной вообще, и рискуйте загрузкой данных дважды (и, возможно, двумя разными потоками, работающими на разных копиях);

Сериализация доступа к кешу, что означает блокировкувесь кеш просто чтобы загрузитьодин предмет;

Начните изобретать велосипед просто, чтобы получить несколько дополнительных методов.

Пояснение: пример временной шкалы

Скажем, когда приложение запускается, ему нужно загрузить 3 набора данных, каждый из которых занимает 10 секунд для загрузки. Рассмотрим следующие два графика времени:

00:00 - Start loading Dataset 1
00:10 - Start loading Dataset 2
00:19 - User asks for Dataset 2

В приведенном выше случае, если мы не используем какой-либо вид синхронизации, пользователь должен ждать полные 10 секунд данных, которые будут доступны через 1 секунду, потому что код увидит, что элемент еще не загружен в кеш и попробуйте перезагрузить его.

00:00 - Start loading Dataset 1
00:10 - Start loading Dataset 2
00:11 - User asks for Dataset 1

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

Вопрос:

Существуют ли кеширующие библиотеки для .NET (до 4.0), которыеделать реализовать такие атомарные операции, как можно ожидать от поточного кеша?

Или, в качестве альтернативы, существуют ли какие-либо средства для расширения существующего «поточно-ориентированного» кэша для поддержки таких операций,без сериализовать доступ к кешу (что побеждало бы цель использования потокобезопасной реализации в первую очередь)? Я сомневаюсь, что есть, но, возможно, я просто устал и игнорирую очевидный обходной путь.

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

Ответы на вопрос(4)

Ваш ответ на вопрос