HttpRuntime. Лучшие практики кэша

Кроме того, почему в первом объявлении шаблона + класса отсутствует "< S ...>" сразу после объявления структуры? (посмотрите, что закомментировано)? когда это правильно добавлять, а когда нет?

Мне кажется, что лучше начать с этого момента.

Прежде всего, следующее (удалено <S...> прокомментировано) является объявлением (внимание: только объявление, не определение) структуры шаблона Example, которая получает список переменных типа шаблона параметры

template<typename... S>
struct Example; 

Вы также можете избежать использования S и писать просто

template <typename...>
struct Example; 

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

На данный момент компилятор знает, что существует шаблонная структура с переменным числом аргументов Example, но не знает, как это делается.

Затем мы добавляем определение специализации из Example, которые получают один или несколько параметров шаблона (обратите внимание, что Example определено для получения ноля или более параметров, поэтому специализация, которая получает один или несколько параметров, является частным случаем Example)

//....... one --> V          VVVVV <- or more template parameter
template<typename H, typename... T>
struct Example<H, T...>
{ // .........^^^^^^^^^  <- this is a specialization
    static const size_t value = sizeof(H) + Example<T...>::value;
};

Часть <H, T...> после Example идентифицирует специализацию (как сказано).

]

Эта специализация определяет переменную static const size_t, инициализированную суммой sizeof(H) (sizeof() параметра шаблона первого типа) с value, определенным в другом классе Example: Example<T...>. [ 1170]

Итак, вы наблюдаете рекурсивное определение: значение - это сумма sizeof() первого параметра (типа) с суммой sizeof() следующих типов.

Предложение: если вы используете вариационные шаблоны, вы также можете использовать constexpr, поэтому лучше определите value как constexpr

 static constexpr std::size_t value = sizeof(H) + Example<T...>::value;

Или, что лучше, вы можете наследовать от std::integral_constant [1173 ]

template <typename H, typename... T>
struct Example <H, T...> 
   : public std::integral_constant<std::size_t, sizeof(H) + Example<T...>{}>
{ };

, поэтому вы наследуете value из std::integral_constant с дополнительными полезными возможностями (например: автоматическое преобразование в std::size_t в контексте, где требуется std::size_t)

Каждая рекурсия нуждается в наземном обосновании, поэтому у вас есть

template<>
struct Example<>
{
    static const size_t value = 0;
};

декларация другой специализации из Example; на этот раз случай с точно нулевым параметром шаблона (Example<>). В этом случае у вас есть определение value, равное нулю, чтобы завершить рекурсию.

Как и раньше, вы можете определить value как constexpr или, лучше IMHO, снова используя std::integral_constant

template <>
struct Example<> : public std::integral_constant<std::size_t, 0u>
 { };

Теперь вы определили две специализации для Example: одна для одной - или больше вариантов параметров, один для случая нулевых параметров. Итак, вы рассмотрели все случаи для Example, который объявлен получающим ноль или более параметров; нет необходимости объявлять универсальную (не специализированную версию) Example.

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

template <typename...>
struct Example : public std::integral_constant<std::size_t, 0u>
 { };

template <typename T, typename ... Ts>
struct Example<T, Ts...>
 : public std::integral_constant<std::size_t, sizeof(T)+Example<Ts...>{}>
 { };

, вы сначала объявите Example, получая ноль или более параметров и определите общий случай с value нулем (основной случай), затем вы определяете одну или более специализацию.

Учитывая, что компилятор выбирает более специализированную версию (когда подходит больше версий), компилятор выбирает специализацию при наличии одного или нескольких параметров (версии ботов совпадают, но специализация более специализирована) и универсальную версию при наличии являются нулевыми параметрами (потому что специализация не совпадает).

1182] Этот способ немного более синтетический, но может быть менее понятным.

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

Теперь должно быть легко понять.

Когда вы пишете

Example<long, int, char>::value

, вы запрашиваете value из Example<long, int, char>.

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

value = sizeof(long) + Example<int, char>::value;

по той же причине, value в Example<int, char> равно

value = sizeof(int) + Example<char>::value;

] и value в Example<char> равно

value = sizeof(char) + Example<>::value;

Теперь для Example<>::value выбрана специализация нулевых параметров и Example<>::value равно нулю.

Итак, мы имеем, что value в Example<long, int, char> инициализируется с

 value = sizeof(long) + sizeof(int) + sizeof(char) + 0;

Вы пометили C ++ 11, поэтому жаль, что вы не можете использовать C ++ 17 (сворачивание шаблонов ), где вы можете вообще избежать рекурсии и определить Example как using

template <typename ... Ts>
using Example = std::integral_constant<std::size_t, (... + sizeof(Ts))>;
20
задан Wesley 18 May 2009 в 06:27
поделиться

3 ответа

Согласно этой документации http://msdn.microsoft.com/en-us/library/system .web.caching.cache (VS.80) .aspx доступ к объекту кэша является потокобезопасным. Что касается объектов, которые вы храните в потоке кэша, безопасность должна исходить откуда-то еще.

8
ответ дан 30 November 2019 в 01:06
поделиться

Я не думаю, что необходимо связывать доступ к свойству HttpRuntime.Cache с блокировкой, как .Cache свойство является статическим, а также поточно-ориентированным.

Существует много различных способов доступа к объекту Cache (HttpRuntime.Cache, HttpContext.Current.Cache, Page.Cache и т. д.). Все они обращаются к одному и тому же объекту Cache, поскольку в каждом домене приложения имеется только один объект Cache, поскольку он эффективно поддерживает потокобезопасный объект Singleton.

2
ответ дан 30 November 2019 в 01:06
поделиться

В этой статье предлагается использовать блокировку:

http://msdn.microsoft.com/en-us/magazine/cc500561.aspx

Цитата:

Проблема в том, что если у вас есть { {1}} запрос, который занимает 30 секунд, и вы выполняете страницу каждую секунду, в течение времени, необходимого для заполнения элемента кеша , 29 других запросов будут { Входят {1}}, и все они будут пытаться заполнить элемент кэша своими собственными запросами к базе данных. Чтобы решить эту проблему, вы можете добавить блокировку потока, чтобы остановить выполнение других страниц при запросе данных из базы данных.

Вот их фрагмент кода:

// check for cached results
object cachedResults = ctx.Cache["PersonList"];
ArrayList results = new ArrayList();

if  (cachedResults == null)
{
  // lock this section of the code
  // while we populate the list
  lock(lockObject)
  {
    cachedResults = ctx.Cache["PersonList"];
    // only populate if list was not populated by
    // another thread while this thread was waiting
    if (cachedResults == null)
    {
      cachedResults = ...
      ctx.Cache["PersonList"] = cachedResults;
    }
  }
}

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

10
ответ дан 30 November 2019 в 01:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: