Имеют ли pthreads какие-либо преимущества перед GCD?

Недавно изучив Grand Central Dispatch, я обнаружил, что многопоточный код довольно интуитивно понятен (с GCD). Мне нравится тот факт, что никаких блокировок не требуется (и тот факт, что он использует внутренние структуры данных без блокировки) и что API очень прост.

Сейчас я начинаю изучать потоки pthread, и я не могу не быть немного ошеломлен их сложностью. Соединения потоков, мьютексы, условные переменные - все это не обязательно в GCD, но имеет много вызовов API в pthreads.

Имеют ли pthreads какие-либо преимущества перед GCD? Это более эффективно? Существуют ли обычные варианты использования, когда потоки pthread могут делать то, что не может делать GCD (за исключением программного обеспечения уровня ядра)?

Что касается кроссплатформенной совместимости, меня это не особо беспокоит. В конце концов, libdispatch имеет открытый исходный код, Apple внесла свои изменения закрытия в качестве исправлений в GCC, clang поддерживает закрытие, и уже (например, FreeBSD) мы начинаем видеть некоторые реализации GCD, не принадлежащие Apple. Меня больше всего интересует использование API (конкретные примеры были бы отличными!).


person Mike    schedule 27.01.2010    source источник
comment
Это кажется актуальным: stackoverflow.com/questions/14177689/   -  person user1031420    schedule 30.05.2013


Ответы (6)


Это потрясающее чувство, которое вы испытываете ... именно поэтому был изобретен GCD.

На самом базовом уровне есть потоки, pthreads - это POSIX API для потоков, поэтому вы можете писать код в любой совместимой ОС и ожидать, что он будет работать. GCD построен на основе потоков (хотя я не уверен, действительно ли они использовали pthreads в качестве API). Я считаю, что GCD работает только на OS X и iOS, и это в двух словах является его основным недостатком.

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

person slebetman    schedule 27.01.2010
comment
Так что, кроме кросс-платформенной совместимости, нет никаких недостатков в использовании GCD (даже скорости)? - person Mike; 27.01.2010
comment
Собственно, скорость - одно из преимуществ GCD перед наивным использованием pthreads. Даже сложные самореализующиеся пулы потоков в pthreads, таких как Apache, редко бывают так хороши, как GCD, потому что GCD лучше знает ОС и базовое оборудование. - person slebetman; 27.01.2010
comment
Библиотеки Pthreads работают так же быстро, как и разработчики. Они должны быть написаны специально для ОС и архитектуры ЦП (атомарные операции во избежание состояния гонки сильно зависят от архитектуры). Это не универсальная библиотека, которую можно компилировать в любой системе. - person Chris S; 27.01.2010
comment
@Chris: Как уже упоминалось, GCD строится на основе потоков, а не альтернативной реализации. По сути, это пулы потоков, реализованные ОС, где ОС решает, сколько потоков создавать и сколько задач фактически запланировано, а не распределяется по потокам. Следовательно, независимо от того, насколько быстры pthreads на данной платформе, такое решение, как GCD, всегда, по крайней мере теоретически, будет быстрее. Если вы попытаетесь оптимизировать многопоточное приложение для повышения производительности до уровня того, что сделали Apache2 и NginX, вы закончите эмуляцию GCD, но без помощи ОС для управления пулами. - person slebetman; 27.01.2010
comment
@slebetman: Как только потоки будут созданы, ОС будет обрабатывать их так же, как и любой другой поток, неважно, какая библиотека их создала. Таким образом, GCD и потоки Pthread после создания будут работать с одинаковой скоростью. Теперь, если GCD реализует свои собственные мьютексы, они могут быть быстрее или медленнее, чем ручные мьютексы pthread (это будет в основном зависеть от программирования). GCD управляет созданием потока и сам отменяет его, поэтому он может предложить или не предоставить оптимальное решение; то же самое можно сказать и о pthreads, за исключением того, что программист несет ответственность за создание / отмену с помощью pthreads и может потенциально оптимизировать приложение. - person Chris S; 27.01.2010
comment
Согласно документации Apple, настоящие преимущества GCD - это «управление». Довольно сложно настроить и оптимизировать пул потоков вручную. GCD делает это. И реализация Apple GCD интегрирована с ядром, а не поверх pthreads. - person eonil; 29.08.2010
comment
Даже совместимость не проблема. GCD - это библиотека с открытым исходным кодом под названием libdispatch, поэтому вы можете скомпилировать ее с каждым проектом (по крайней мере, для UNIX-совместимых систем, без изменений). - person Constantino Tsarouhas; 24.11.2012
comment
Еще одна тонкость заключается в том, что потоки GCD на самом деле не реализуют всю семантику pthread. Есть несколько вызовов pthread_ *, которые просто помечены как не вызывающие его из очереди GCD. Я не осведомлен о каком-либо ускорении из-за этого (в основном это просто для того, чтобы пул потоков мог правильно управлять ими), но готовность нарушить семантику pthread может помочь в некоторых случаях. С другой стороны, система приоритетов GCD не такая детализированная, как потоки pthread. - person Catfish_Man; 09.12.2012

Я иду с другой стороны: начал использовать pthreads в своем приложении, которое я недавно заменил на std::thread из C ++ 11. Теперь я играю с конструкциями более высокого уровня, такими как псевдо-ускоренный пул потоков, и даже более абстрактным, Intel Стандартные блоки потоков. Я бы посчитал, что GCD будет на уровне или даже выше, чем TBB.

Несколько комментариев:

  • imho, pthread не сложнее, чем GCD: по сути, pthread фактически содержит очень мало команд (всего несколько: использование только тех, которые упомянуты в OP, даст вам 95% + функциональности что вам когда-нибудь понадобится). Как и любая библиотека нижнего уровня, то, как вы их собираете и как вы используете, дает вам всю силу. Не забывайте, что в конечном итоге библиотеки, такие как GCD и TBB, будут вызывать библиотеку потоков, например pthreads или std::thread.
  • иногда успех или неудача зависит не от того, что вы используете, а от того, как вы это используете. Как сторонники библиотеки, TBB или GCD расскажут вам обо всех преимуществах использования их библиотек, но пока вы не опробуете их в контексте реального приложения, все это будет теоретической пользой. Например, когда я прочитал о том, как легко использовать мелкозернистый parallel_for, я сразу же применил его в задаче, для которой, как мне казалось, можно было бы извлечь выгоду из параллелизма. Естественно, меня тоже привлек тот факт, что TBB будет обрабатывать все детали об оптимальной балансировке нагрузки и распределении потоков. Результат? TBB занял в пять раз больше времени, чем однопоточная версия! Но я не виню TBB: оглядываясь назад, очевидно, что это случай неправильного использования parallel_for: когда я читал мелкий шрифт, я обнаружил накладные расходы, связанные с использованием parallel_for, и предположил, что в моем случае затраты на переключение контекста и добавленные вызовы функций перевешивают преимущества использования нескольких потоков. Поэтому вы должны профилировать свое дело, чтобы увидеть, какой из них будет работать быстрее. Возможно, вам придется реорганизовать свой алгоритм, чтобы использовать меньше накладных расходов на потоки.
  • почему это происходит? Как pthread или никакие потоки могут быть быстрее, чем GCD или TBB? Когда дизайнер проектирует GCD или TBB, он должен делать предположения о среде, в которой будут выполняться задачи. Фактически, библиотека должна быть достаточно общей, чтобы она могла обрабатывать странные, непредвиденные варианты использования со стороны разработчика. Эти общие реализации не будут бесплатными. С другой стороны, библиотека будет запрашивать оборудование и текущую рабочую среду, чтобы лучше сбалансировать нагрузку. Будет ли это работать вам на пользу? Единственный способ узнать это - попробовать.
  • есть ли польза от изучения низкоуровневых библиотек, таких как std::thread, когда доступны высокоуровневые библиотеки? Ответ - громкое ДА. Преимущество использования высокоуровневых библиотек заключается в абстракции от деталей реализации. Недостатком использования высокоуровневых библиотек также является абстракция от деталей реализации. При использовании pthreads я в высшей степени осведомлен об общем состоянии и времени жизни объектов, потому что, если я ослаблю бдительность, особенно в проекте среднего или большого размера, я могу очень легко получить условия гонки или сбои памяти. Эти проблемы исчезнут, когда я использую библиотеку более высокого уровня? Не совсем. Похоже, мне не нужно думать о них, но на самом деле, если я буду небрежно с этими деталями, реализация библиотеки также выйдет из строя. Таким образом, вы обнаружите, что если вы понимаете конструкции нижнего уровня, все эти библиотеки действительно имеют смысл, потому что в какой-то момент вы будете думать о их реализации самостоятельно, если будете использовать вызовы нижнего уровня. Конечно, на этом этапе обычно лучше использовать проверенный и отлаженный библиотечный вызов.

Итак, давайте разберем возможные реализации:

  • Вызовы библиотеки TBB / GCD: наибольшее преимущество для новичков в многопоточности. У них более низкие барьеры для входа по сравнению с изучением библиотек более низкого уровня. Однако они также игнорируют / скрывают некоторые ловушки использования многопоточности. Динамическая балансировка нагрузки сделает ваше приложение более переносимым без дополнительного программирования с вашей стороны.
  • Вызовы pthread и std::thread: на самом деле нужно изучить очень мало вызовов, но их правильное использование требует внимания к деталям и глубокого понимания того, как работает ваше приложение. Если вы можете понимать потоки на этом уровне, API-интерфейсы высокоуровневых библиотек, безусловно, будут иметь больше смысла.
  • Однопоточный алгоритм: давайте не будем забывать о преимуществах простого однопоточного сегмента. Для большинства приложений однопоточность проще для понимания и гораздо менее подвержена ошибкам, чем многопоточность. Фактически, во многих случаях это может быть правильный выбор дизайна. Дело в том, что реальное приложение проходит через различные фазы многопоточности и фазы однопоточности: возможно, нет необходимости постоянно быть многопоточным.

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

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

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

person kfmfe04    schedule 30.12.2011

GCD - это технология Apple, не самая кроссплатформенная; pthread доступны практически во всем, начиная с OSX, Linux, Unix, Windows ... включая этот тостер

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

person Chris S    schedule 27.01.2010
comment
Меня не слишком заботит кроссплатформенная совместимость. В конце концов, GCD - это открытый исходный код, и FreeBSD уже приняла его (хотя и как несовершенную реализацию). Меня больше интересует написание параллельных программ. Существуют ли случаи, когда параллелизм пула потоков неприменим? Меня особенно интересуют конкретные примеры. - person Mike; 27.01.2010
comment
FreeBSD активно портирует CGD (на самом деле libdispatch, вы не можете перенести товарный знак, поскольку это не код). Что касается компилятора, Apple уже отправила исправления в gcc для поддержки синтаксиса закрытия, который поддерживает GCD. - person slebetman; 27.01.2010
comment
Параллелизм пула потоков отлично подходит для небольших / коротких рабочих нагрузок. Многие веб-серверы построены таким образом, потому что большинство запросов страниц требуют минимальной обработки. Для приложений с различными ролями пользователей (подумайте о средствах ввода и вывода, а не о людях-пользователях) вам могут понадобиться очень разные потоки для обработки каждого. Например, ваше приложение может иметь поток управления дисковым кешем, поток пользовательских подключений и поток очереди обработки. Это позволит вашей программе использовать преимущества многоядерных процессоров. Если GCD делает то, что вам нужно, придерживайтесь его, это проще. Pthreads имеют больше возможностей и сложности - person Chris S; 27.01.2010
comment
Для вашего примера, не имеет ли смысл использовать прослушиватели событий GCD (с соответствующими файловыми дескрипторами), а не выделять отдельные потоки? - person Mike; 27.01.2010
comment
Что ж, давайте на мгновение предположим, что вам нужны только три потока, упомянутые в примере. Используя GCD, вам нужно, чтобы обработчик определил, какой тип функции вы хотите выполнить, а затем вызвал бы правильную функцию. Также может быть интересна реализация асинхронного ввода-вывода. - person Chris S; 27.01.2010

Как и любой декларативный подход с поддержкой, например openmp или Intel TBB GCD должен быть очень хорош в досадно параллельном проблемы и, вероятно, будет легко победить наивную параллельную сортировку, запрограммированную вручную. Я бы посоветовал вам все же изучить pthreads. Вы лучше поймете параллелизм, вы сможете применить правильный инструмент в каждой конкретной ситуации, и если ничего другого - существует масса кода, основанного на pthread, - вы сможете читать «устаревший» код.

person Nikolai Fetissov    schedule 27.01.2010

Обычно: одна задача на каждую реализацию Pthread использует мьютексы (функция ОС).
GCD: 1 задача на блок, сгруппированы в очереди. 1 поток на виртуальный ЦП может получить очередь и выполнять все задачи без мьютексов. Это снижает накладные расходы на управление потоками и мьютекс, что должно повысить производительность.

person Andy Jackson    schedule 23.09.2010

GCD абстрагирует потоки и предоставляет вам очереди отправки. Он создает потоки по своему усмотрению с учетом количества доступных ядер процессора. GCD имеет открытый исходный код и доступен через библиотеку libdispatch. FreeBSD включает libdispatch начиная с версии 8.1. GCD и C Blocks - это мэрский вклад Apple в сообщество программистов C. Я бы никогда не стал использовать ОС, не поддерживающую GCD.

person ColemanCDA    schedule 15.07.2013