2015-10-11 4 views
1

Я видел много примеров кеширования, которые включают блокировку. Я пытаюсь кэшировать общий список для всего приложения. Мне действительно нужно использовать блокировки, как показано ниже? Самое худшее может случиться, если я не использую блокировку;Нужно ли нам блокировать при кешировании в приложении asp.net mvc?

Если несколько потоков обнаружения промаха кэша в примерно такой же time.They может попытаться загрузить данные simultaneously.In вывод, данные будут такими же ...

Это правда?

public class Worker 

{ 

    private static object someLock; 

    public static object CacheMethod() 
    { 

     var results = HttpContext.Current.Cache["Common"]; 

     if (results == null) 
     { 
      lock (someLock) 
      { 
       results = HttpContext.Current.Cache["Common"]; 
       if (results == null) 
       { 
        results = GetResultsFromSomewhere(); 
        HttpContext.Current.Cache.Insert("Common", results, null, 
          DateTime.Now.AddHours(1), Cache.NoSlidingExpiration); 
       } 
      } 
     } 
     return results; 

    }`` 

ответ

1

Эта блокировка используется для предотвращения штамповки кеша. Если кеш пуст и занимает некоторое время, чтобы заполнить, все входящие запросы начнут заполнять кеш. В зависимости от того, как работают номера, которые могут быть катастрофической потерей производительности.

Если GetResultsFromSomewhere был Thread.Sleep(10000), тогда это может случиться.

Плохая вещь об этом конкретном коде заключается в том, что это одна блокировка для всех ключей кеша. Обычно вам нужен один замок на ключ.

+0

Если я не использую блокировку, сценарий будет таким; Если пользовательский запрос видит этот кеш null, он будет вызывать GetResultsFromSomewhere, который занимает 10 секунд. В то же время пользователь B делает то же самое и ждет 10 секунд. Но я использую блокировку, сценарий будет таким; Пользователь A захватывает блокировку, и пользователь B будет ждать, когда этот замок будет выпущен. Он будет примерно ждать 10 секунд снова. Так что мне кажется, что не будет такой потери производительности. Я не прав? – erhan355

+0

«В то же время пользователь B делает то же самое и ждет 10 секунд» Нет, пользователь B также вызывает GetResultsFromSomewhere. Теперь у нас есть два таких вызова и в два раза больше использования ресурсов. Как вы думаете, почему пользователь B будет ждать? – usr

+0

Я попытался сказать, что пользователь B вызовет GetResultsFromSomewhere и дождитесь, пока операция вернет результат, и он снова займет 10 секунд. Если я использую блокировку, чем это время, пользователь B ждет, когда пользователь A выйдет из замка, и это займет 10 секунд. Как-то, пользователь B ждет примерно 10 секунд. На мой взгляд, разница между кешированием с блокировкой и без блокировки невелика. Есть ли там? – erhan355

0

Это называется double-checked locking pattern. Да, это правда, что если у вас много запросов, и данные занимают больше времени, чем время между запросами, у вас может быть несколько запросов на одни и те же данные.

Без блокировки каждая дополнительная нить получает одни и те же данные, поэтому количество CPU/сетевой активности/ОЗУ, используемое дополнительными потоками, просто теряется. Независимо от того, является ли это проблемой, зависит от того, сколько трафика имеет ваш сайт и доступных ресурсов сервера/сети.

Однако гораздо важнее убедиться, что ваш объект results является потокобезопасным, потому что вы гарантированно имеете несколько потоков, взаимодействующих с его состоянием. Самый простой способ - сделать все свои свойства доступными только для чтения, но если вам нужны доступные для записи свойства, вы можете использовать ReaderWriterLockSlim в сочетании с методами, обеспечивающими атомарные действия (см. Примеры в ссылке).

Смежные вопросы