Заблокирует () блок операторов все потоки в process/appdomain?

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

Так, если у меня есть 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? Или так же, как у меня есть потоки?

11
задан Cœur 5 August 2017 в 10:21
поделиться

6 ответов

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

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

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

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

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

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

11
ответ дан 3 December 2019 в 07:36
поделиться

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

2
ответ дан 3 December 2019 в 07:36
поделиться

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

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

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

где:

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

блок операторов операторы критического раздела.

2
ответ дан 3 December 2019 в 07:36
поделиться

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

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

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

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

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

1
ответ дан 3 December 2019 в 07:36
поделиться

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

Сколько их будет в каждый момент времени, определить сложно.

0
ответ дан 3 December 2019 в 07:36
поделиться

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

0
ответ дан 3 December 2019 в 07:36
поделиться
Другие вопросы по тегам:

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