Как справиться с дорогостоящими операциями построения с помощью MemoryCache?

В ASP.NET MVC у нас есть несколько экземпляров данных, для построения которых требуется много ресурсов и времени. Мы хотим их кэшировать.

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

var data = cache["key"];
if(data == null)
{
  data = buildDataUsingGoodAmountOfResources();
  cache["key"] = data;
}

Как вы можете видеть, на загруженном веб-сайте сотни потоков могут выполняться внутри оператора if одновременно, пока данные не будут построены, что сделает операцию построения еще медленнее, излишне потребляя ресурсы сервера.

Существует атомарная реализация AddOrGetExistingв MemoryCache, но она неправильно требует «устанавливаемого значения» вместо «кода для извлечения устанавливаемого значения», что, по моему мнению, делает данный метод почти полностью бесполезным.

Мы использовали нашу собственную специальную структуру вокруг MemoryCache, чтобы сделать это правильно, однако для этого требуются явные блокировкиs. Использование объектов блокировки для каждой записи обременительно, и мы обычно избавляемся от совместного использования объектов блокировки, что далеко от идеала. Это навело меня на мысль, что причины избегать такого соглашения могут быть преднамеренными.

Итак, у меня есть два вопроса:

  • Не лучше ли не блокироватьстроительный код? (Интересно, это могло бы оказаться более чувствительным для одного)

  • Каков правильный способ добиться блокировки каждой записи для MemoryCache для такой блокировки? Сильное желание использовать строку keyв качестве объекта блокировки отклоняется в «блокировке .NET 101».

58
задан abatishchev 18 February 2016 в 20:43
поделиться