2009-10-18 1 views
21

Я где-то читал (больше не могу найти страницу), что блокировка свободных структур данных более эффективна «для определенных рабочих нагрузок», что, по-видимому, означает, что иногда они на самом деле медленнее или выигрыш от них может быть нулевым в некоторых ситуациях. Принимая 100-секундный удар команды блокировки для выполнения атомарного op, мне кажется намного быстрее, чем спать, и ожидая, когда планировщик пробудит процесс резервного копирования, поэтому для меня не очевидно, при каких обстоятельствах структура данных без блокировки было бы менее предпочтительным, чем старомодные мьютексы. Если блокировка доступна в 99% случаев, и процесс не должен идти спать, значит, это мьютекс быстрее? Есть ли правильное правило большого пальца, чтобы узнать, какой способ пойти, если будет создана подходящая структура данных без блокировки?Когда блоки данных без блокировки менее эффективны, чем взаимное исключение (мьютексы)?

+2

Да, эмпирическое правило заключается в сопоставлении обоих подходов. –

+2

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

+3

«Для определенных рабочих нагрузок» также может быть интерпретировано как «для тех рабочих нагрузок, которые могут быть синхронизированы с блокированной структурой данных». Другими словами, они всегда быстрее, но не всегда могут применяться. –

ответ

48

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

Это может сработать, если производство нового объекта дешево, а уровень конкуренции достаточно низкий, что обычно работает CompareExchange. Если есть значительный спор, и если создание нового объекта происходит медленно, одновременные попытки обновления по N потокам могут занять N^2 раза. В качестве экстремального примера предположим, что 100 потоков запущены на процессоре, обновление занимает 100 мс времени процессора (чуть больше фрагмента времени), и все 100 потоков пытаются обновить объект за один раз. В течение первых десяти секунд каждый поток будет создавать новый объект на основе оригинала. Один из потоков успешно выполнит CompareExchange, в то время как другие будут терпеть неудачу. Затем в течение следующих 9.9 секунд 99 потоков будут генерировать новые версии объекта, после чего он успешно опубликует свое обновление и 98 завершится с ошибкой. Чистый эффект будет заключаться в том, что метод блокировки будет занимать 505 секунд процессорного времени, чтобы выполнить 100 обновлений, когда система блокировки могла сделать их примерно через 10 секунд.

+0

+1 за лучший ответ. –

+0

Спасибо. Бывают моменты, когда наилучшая производительность может быть достигнута с использованием комбинации методов блокировки и блокировки: сохранить взаимосвязанную совокупность того, сколько попыток создания и try-swap были сделаны потоками, которые еще не преуспели; если это число становится достаточно высоким, каждый, кто хочет изменить ресурс, должен уйти, пока не приобретет блокировку. Блокировка не требуется для предотвращения коррупции, но приведет к сериализации доступа и предотвращению конфликтов. Этот подход является сложным, и он теряет некоторые из преимуществ незакрепленного кодирования (например, выживает, если поток испаряется), но он может быть полезен в любом случае. – supercat

+0

Интересный ответ. Я думал о том, как это можно обобщить для большего количества процессоров. Правильно ли я считаю, что мьютексы быстрее в описанном сценарии будут правдивыми, если у вас меньше процессоров, чем потоки? Кажется, что если у вас есть тот же номер, нет никакого штрафа, чтобы позволить этим потокам пытаться сравнивать и обменивать снова и снова. Если вы суммируете количество секунд, затрачиваемых каждым процессором, это выглядит хуже, но время настенных часов от начала до конца все равно будет короче. –

5

Не знаю, как сделать это медленнее, но это, конечно, затрудняет право. Во многих случаях, когда два подхода практически идентичны по производительности (или когда это просто не имеет значения, если требуется 500 пикосекунд, а не 100 пикосекунд), выберите самый простой подход - обычно lock.

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

Обратите также внимание на то, что в некоторых средах предусмотрен уровень блокировки выше мьютекса, предоставляемого OS; mutex, но без некоторых накладных расходов (например, Monitor в .NET).

+0

Вы имели в виду «практически идентичные»? –

+0

lol! Да, в самом деле. Или они могут быть одинаковой высоты; -p –

7

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

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

1

Я хотел бы добавить один балл к этой части ответа: «Если мьютекс или критическая секция медленная, это когда сбой блокировки (есть конфликт). В этом случае ОС также вызывает планировщик, чтобы приостановить поток до тех пор, пока объект исключения не будет выпущен ».

Похоже, что разные операционные системы могут иметь разные подходы к тому, что делать, если сбор блокировки не удался. Я использую HP-UX, и он, например, имеет более сложный подход к блокировке мьютексов. Вот его описание:

... С другой стороны, изменение контекста является дорогостоящим процессом. Если ожидание будет коротким, мы бы предпочли не использовать контекстный переключатель. Чтобы сбалансировать эти требования, когда мы пытаемся получить семафор и находим его заблокированным, первое, что мы делаем, это короткое ожидание вращения.Подпрограмма psema_spin_1() вызывается для вращения до 50 000 тактов, чтобы получить блокировку. Если мы не получим блокировку после 50 000 циклов, мы тогда вызываем psema_switch_1(), чтобы отказаться от процессора и позволить другому процессу взять верх.

1

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

Лучше всего подумать, нужно ли вам разрешать нескольким потокам ждать доступа к некоторому набору операций или блокировать до тех пор, пока не будет сигнализирован. Для каждого из них требуется очередь ожидающих потоков. Первые очереди представляют собой очереди, ожидающие доступа к синхронизированной области, в то время как последний ставит в очередь потоки, ожидающие сигнала. Классы Java AbstractQueuedSynchronizer и AbstractQueuedLongSynchronizer предоставляют такую ​​очередь, в частности: CLH Queue -upon, в которой можно создавать мьютексы, условия и другие примитивы на основе очереди.

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

+0

Мьютекс для меня подразумевает, что, когда блокировка не может быть приобретена, ОС помещает поток в спящий режим и отвечает за его пробуждение только после того, как мьютекс доступен, и в этот момент I «Говорите, что дихотомия имеет смысл. Блокировка свободных операций никогда не уступает ОС (хотя ОС по-прежнему может быть выгружена ОС оперативно). Но я предполагаю, что если бы у вас была двухпоточная система с минимальной (или нет) ОС, она могла бы реализовать «мьютексы», вращаясь. –

+0

Да, я согласен с вами в том, что это было бы странным подходом к реализации мьютекса * без * парковки очереди в очереди, но я согласен с тем, что обычно используется мьютекс с точки зрения блокировки структур, поскольку можно 't строит блокировки из замков (или черепах) без дна. Оглядываясь назад, мой ответ был мотивирован тем, что он хотел, чтобы ОП рассмотрел, нужно ли ему * блокировать поведение * или нет, чтобы контролировать эксклюзивный доступ. – seh

+0

Ваша терминология в первом абзаце неверна (это не отменяет остальную часть ответа). «lock-free» означает не просто использование атомных операций. Это означает, что по крайней мере один поток всегда может добиться прогресса. Мьютекс не блокируется, даже если вы откатываетесь от атомистики, потому что процесс, удерживающий блокировку, может быть отменен или заблокирован при ошибке страницы или что-то еще. См. Https://en.wikipedia.org/wiki/Non-blocking_algorithm для определения блокировки (по крайней мере, один поток может добиться прогресса) против ожидания (все потоки всегда могут прогрессировать, поэтому никакие циклы повторения cmpxchg или аналогичный). –

0

Эффективность зависит от показателя. Алгоритмы Lock- или wait-free важны в системах, где preemption может ввести тупик или повлиять на сроки составления расписания. В этих случаях обработка менее важна, чем правильность.

ОП рассматривает блокировку в качестве альтернативы мьютексам. Некоторые алгоритмы не требуют ни для доступа к общей структуре данных. В этих случаях как производитель, так и потребитель могут одновременно обращаться к одной и той же структуре данных, не обращая внимания на другую. Пример shared queue позволяет одному читателю и одному писателю одновременно действовать на общий экземпляр. Это отвечает общей потребностям драйвера устройства, записывающего данные, которые потребительский процесс может получить по требованию.

Более сложные отношения между процессами могут быть разрешены (see Herlihy (1991) for an analysis) с различным уровнем аппаратной поддержки.Он заключает Беспошлинная синхронизация представляет собой качественный разрыв с традиционными методами блокировки для реализации параллельных объектов.

Что это значит, так это то, что остается компромисс, но не просто между выбором между мьютексами и прямыми замками.

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

+0

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

+0

@Walter Абсолютно - иногда беспокоиться о том, что отдельные данные не нужны при обработке последовательности. Я понимаю, что мой ответ не учитывал производительность как мьютексов, так и блокировок. Дело в том, что прыжки между рогами дилеммы обеспечивают третью и часто заслуживающую доверия альтернативу. – Pekka

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