Будет ли оператор lock () блокировать все потоки в процессе / домене приложения? - PullRequest
11 голосов
/ 08 июня 2010

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

Итакесли у меня есть 10 серверов и 10 запросов одновременно, приходящих на каждый сервер, то это 100 запросов по всей ферме.Без блокировки это 100 запросов к базе данных.

Если я сделаю что-то вроде этого:

private static readonly object myLockHolder = new object();
if (Cache[key] == null)
{
   lock(myLockHolder)
   {
      if (Cache[key] == null)
      {
         Cache[key] = LengthyDatabaseCall();
      }
   }
}

Сколько запросов к базе данных я сделаю?10?100?Или сколько у меня тем?

Ответы [ 6 ]

11 голосов
/ 08 июня 2010

У вас есть иерархия объектов:

  • У вас есть серверы (10)
  • На каждом сервере у вас есть процессы (вероятно, только 1 - ваш пул служб / приложений)
  • В каждом процессе у вас есть потоки (вероятно, много)

Ваш код будет только запрещать потокам в рамках одного процесса на одном и том же сервере доступ к изменению объекта Cache одновременно. Вы можете создавать блокировки между процессами и даже серверами, но стоимость значительно возрастает по мере продвижения вверх по иерархии.

Использование оператора lock на самом деле lock не приводит ни к каким потокам. Однако, если один поток выполняет код внутри блокировки (то есть в блоке кода после оператора lock), любой другой поток, который хочет взять блокировку и выполнить тот же код, должен ждать, пока первый поток, удерживающий блокировку покидает блок кода и снимает блокировку.

В операторе C # lock используется критическая секция Windows , которая представляет собой легкий механизм блокировки. Если вы хотите заблокировать процессы, вы можете вместо этого использовать mutex . Для блокировки между серверами вы можете использовать базу данных или общий файл.

Как отметил dkackman, в .NET есть концепция AppDomain, которая является своего рода легковесным процессом. Вы можете иметь несколько доменов приложений на процесс. Оператор C # lock блокирует только ресурс в пределах одного AppDomain, и правильное описание иерархии будет включать AppDomain ниже процесса и над потоками. Однако довольно часто в процессе используется только один AppDomain, что делает это различие несколько несущественным.

2 голосов
/ 08 июня 2010

Блокировка не блокирует темы. Это блокировка некоторого экземпляра объекта. И каждый поток, который пытается получить к нему доступ, блокируется. Таким образом, в вашем случае будет заблокирован каждый поток, который будет пытаться получить доступ к myLockHolder, а не все потоки. Другими словами, мы можем сказать, что оператор Lock является синтаксическим сахаром для использования Critical Section .

Как вы можете видеть в MSDN:

оператор блокировки (выражения) block

где:

выражение Указывает объект, который вы хотите заблокировать. выражение должно быть ссылочным типом. Как правило, Выражение будет либо это, если вы хотите защитить переменную экземпляра, или typeof (класс), если вы хотите защитить статическую переменную (или если критическая секция происходит в статическом метод в данном классе).

блок операторов операторы критической секции.

2 голосов
/ 08 июня 2010

Оператор C # lock блокирует конкретный экземпляр объекта (объект, который вы создали с помощью new object()).Объекты (в большинстве случаев) не являются общими для доменов приложений, поэтому если у вас есть 10 серверов, 10 потоков могут одновременно работать с вашей базой данных с помощью этого фрагмента кода.

1 голос
/ 08 июня 2010

lock заблокирует все потоки в этом приложении от доступа к объекту myLockHolder.

Таким образом, если у вас есть 10 запущенных экземпляров приложения, вы получите 10 запросов к серверу, пока объект заблокирован на каждом. Как только вы выйдете из оператора блокировки, следующий запрос будет обработан в этом приложении, но если Cache[key] не равно null, он не будет обращаться к базе данных ..

Количество реальных запросов, которые вы получаете, зависит от того, что здесь происходит:

  if (Cache[key] == null)
  {
     Cache[key] = LengthyDatabaseCall();
  }

Если LengthyDatabaseCall(); завершится неудачно, следующий запрос попытается получить доступ к серверу базы данных и получить информацию, так что на самом деле ваш лучший сценарий состоит в том, что к серверу будет только 10 запросов.

0 голосов
/ 08 июня 2010

Ваша БД получит 10 запросов, с хорошими шансами, что запросы 2-10 будут выполняться намного быстрее, чем запрос 1.

0 голосов
/ 08 июня 2010

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

сколько их в любой момент времени определить сложно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...