Спин-блокировки, насколько полезный они?

Так в основном Вы ищете, какие каталоги имеют много файлов? Вот первый удар в нем:

find . -type d -print0 | xargs -0 -n1 count_files | sort -n

, где "count_files" является сценарием оболочки, который делает (благодарит Jonathan)

echo $(ls -a "$1" | wc -l) $1
33
задан Rob Fonseca-Ensor 14 November 2013 в 20:17
поделиться

9 ответов

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

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

35
ответ дан 27 November 2019 в 17:37
поделиться

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

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

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

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

20
ответ дан 27 November 2019 в 17:37
поделиться

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

11
ответ дан 27 November 2019 в 17:37
поделиться

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

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

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

9
ответ дан 27 November 2019 в 17:37
поделиться

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

5
ответ дан 27 November 2019 в 17:37
поделиться

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

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

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

4
ответ дан 27 November 2019 в 17:37
поделиться

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

Я не могу найти никаких причин для использования спин-блокировки в коде C #, работающем в обычном режиме. ОПЕРАЦИОННЫЕ СИСТЕМЫ. Блокировки занятости в основном являются пустой тратой на уровне приложения - вращение может заставить вас использовать весь временной интервал процессора, а блокировка немедленно вызовет переключение контекста, если это необходимо.

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

3
ответ дан 27 November 2019 в 17:37
поделиться

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

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

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

3
ответ дан 27 November 2019 в 17:37
поделиться

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

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

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

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

7
ответ дан 27 November 2019 в 17:37
поделиться
Другие вопросы по тегам:

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