Спинлоки, насколько они полезны? - PullRequest
31 голосов
/ 21 сентября 2009

Как часто вы на самом деле используете спин-блокировки в своем коде? Как часто встречается ситуация, когда использование занятого цикла фактически превосходит использование блокировок?
Лично, когда я пишу какой-то код, который требует безопасности потоков, я склонен сравнивать его с различными примитивами синхронизации, и, насколько это возможно, использование блокировок дает лучшую производительность, чем использование спин-блокировок. Независимо от того, как мало времени я фактически удерживаю блокировку, количество разногласий, которые я получаю при использовании спин-блокировок, намного больше, чем количество, которое я получаю от использования блокировок (конечно, я запускаю свои тесты на многопроцессорной машине).

Я понимаю, что более вероятно встретить спин-блокировку в «низкоуровневом» коде, но мне интересно узнать, считаете ли вы его полезным даже в более высокоуровневом программировании?

Ответы [ 10 ]

32 голосов
/ 21 сентября 2009

Это зависит от того, что вы делаете. В общем коде приложения вам нужно избегать спин-блокировок.

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

20 голосов
/ 21 сентября 2009

В C # "спин-блокировки", по моему опыту, почти всегда хуже, чем взятие блокировки - это редкое явление, когда спин-блокировки превосходят блокировку.

Однако это не всегда так. .NET 4 добавляет структуру System.Threading.SpinLock . Это дает преимущества в ситуациях, когда блокировка удерживается в течение очень короткого времени и повторно захватывается. Из документов MSDN о структурах данных для параллельного программирования :

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

Спин-блокировки могут превзойти другие механизмы блокировки в тех случаях, когда вы делаете что-то вроде блокировки через дерево - если у вас есть блокировки на каждом узле в течение очень и очень короткого периода времени, они могут выполнить традиционную блокировку. замок. Я столкнулся с этим в механизме рендеринга с многопоточным обновлением сцены, в какой-то момент - профилированные спин-блокировки, превосходящие блокировку с помощью Monitor.Enter.

11 голосов
/ 21 сентября 2009

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

9 голосов
/ 21 сентября 2009

My 2c: если ваши обновления удовлетворяют некоторым критериям доступа, то они являются хорошими кандидатами на спин-блокировку:

  • fast , т. Е. У вас будет время приобрести спин-блокировку, выполнить обновления и освободить спин-блокировку в виде однопотоковых квантов, чтобы вы не получили приоритет при удержании спин-блокировки
  • локализовано все данные, которые вы обновляете, предпочтительно находятся на одной загруженной странице, вам не нужно пропускать TLB, пока вы удерживаете спин-блокировку, и вы определенно не хотите, чтобы своп считывался при сбое страницы !
  • atomic вам не нужна никакая другая блокировка для выполнения операции, т.е. никогда не ждите блокировки под спин-блокировкой.

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

7 голосов
/ 16 июля 2010

Один из вариантов использования спин-блокировок - если вы ожидаете очень низкую конкуренцию, но их будет много. Если вам не нужна поддержка рекурсивной блокировки, спин-блокировка может быть реализована в одном байте, а если конфликт очень низкий, то потери в цикле ЦП незначительны.

Для практического использования у меня часто есть массивы тысяч элементов, где обновления для различных элементов массива могут безопасно происходить параллельно. Шансы двух потоков на одновременное обновление одного и того же элемента очень малы (низкая конкуренция), но мне нужен один замок для каждого элемента (у меня их будет много). В этих случаях я обычно выделяю массив ubytes того же размера, что и массив, который я обновляю параллельно, и реализую встроенные спин-блокировки (на языке программирования D):

while(!atomicCasUbyte(spinLocks[i], 0, 1)) {}
    myArray[i] = newVal;
atomicSetUbyte(spinLocks[i], 0);

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

5 голосов
/ 21 сентября 2009

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

4 голосов
/ 21 сентября 2009

Обратите внимание на следующие моменты:

  1. Большинство реализаций mutexe вращаются в течение некоторого времени, прежде чем поток фактически не запланирован. Из-за этого трудно сравнивать эти мьютексы с чистыми спинлоками.

  2. Несколько потоков, вращающихся «как можно быстрее» на одном и том же спин-блокировке, будут занимать всю полосу пропускания и резко снижать эффективность вашей программы. Вам нужно добавить крошечное «спящее» время, добавив noop в цикле вращения.

3 голосов
/ 12 июня 2010

Я использовал спин-блокировки для фазы остановки мусора в моем проекте HLVM , потому что они просты, и это - игрушечная виртуальная машина. Однако спин-блокировки могут быть контрпродуктивными в этом контексте:

Одна из ошибок в сборщике мусора компилятора Glasgow Haskell настолько раздражает, что у него есть имя " последнее замедление ядра ". Это является прямым следствием их неуместного использования спин-блокировок в их ГХ и усиливается в Linux из-за его планировщика, но на самом деле эффект может наблюдаться, когда другие программы конкурируют за процессорное время.

Эффект очевиден на втором графике здесь и, как видно, влияет не только на последнее ядро ​​ здесь , где программа на Haskell видит снижение производительности за пределами только 5 ядер. 1013 *

3 голосов
/ 21 сентября 2009

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

Я не могу использовать спин-блокировку в коде c #, работающем на нормальной ОС. Занятые блокировки в большинстве случаев являются пустой тратой на уровне приложений - вращение может привести к тому, что вы будете использовать весь временной интервал ЦП, а блокировка немедленно вызовет переключение контекста, если это необходимо.

Высокопроизводительный код, в котором у вас nr потоков = nr процессоров / ядер, может быть полезен в некоторых случаях, но если вам нужна оптимизация производительности на этом уровне, вы, вероятно, делаете 3D-игру следующего поколения, работая на встроенной ОС с плохими примитивами синхронизации , создание ОС / драйвера или в любом случае не использование c #.

0 голосов
/ 12 июня 2019

Всегда помните об этих точках при использовании spinlocks :

  • Быстрое выполнение пользовательского режима.
  • Синхронизирует потоки в рамках одного процесса или нескольких процессов в общей памяти.
  • Не возвращается, пока объект не принадлежит.
  • Не поддерживает рекурсию.
  • Расходует 100% ресурсов ЦП во время "ожидания".

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

Будьте очень, очень осторожны при использовании спинлок

(я не могу это подчеркнуть достаточно).

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