Intel® Threading Building Blocks, OpenMP* или потоки ОС?

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

Среда разработки

Простота/сложность

Код, созданный с использованием модели программирования встроенных потоков, отличается значительно большей сложностью по сравнению с OpenMP или компонентами Intel® Threading Building Blocks (TBB), и его сложнее сопровождать. Одним из преимуществ использования компонентов Intel® TBB или библиотеки OpenMP является то, что эти интерфейсы API создают пул потоков и управляют им: синхронизация и планирование потоков выполняются автоматически.

Языки программирования, поддержка компиляторов и возможности переноса

Если код написан на языке C++, вероятно, Intel® TBB является наилучшим выбором. Intel® TBB особенно хорошо подходит в том случае, если код в значительной степени объектно-ориентирован и в нем широко используются шаблоны C++ и определяемые пользователем типы. Если код написан на C или FORTRAN, лучше выбрать OpenMP, поскольку этот API лучше соответствует стилю структурного программирования, по сравнению с Intel® TBB, и в простых случаях требует меньше затрат на программирование. Однако даже при использовании кода C++, если в алгоритмах преобладают операции обработки массивов, OpenMP может оказаться предпочтительным выбором в сравнении с TBB с точки зрения сложности программирования. Сложность моделей программирования со встроенными потоками на языках C и C++ примерно одинакова. Однако поскольку работа по разбиению на потоки должна быть описана как функция, программирование с использованием встроенных потоков выглядит более естественно на таком языке, как C. В программах на языке C++, в значительной степени ориентированных на объекты, использование встроенных потоков может нарушить стиль и проектное решение, поскольку потоки трудно выразить на языке объектов.

Для Intel® TBB и встроенных потоков не требуется поддержка определенного компилятора, а для OpenMP - требуется. Для использования библиотеки OpenMP необходимо выполнять компиляцию с помощью компилятора, который распознает прагмы OpenMP. Компиляторы Intel® C++ и Fortran поддерживают OpenMP. В последнее время в большинство других компиляторов C++ и Fortran была добавлена, по крайней мере, некоторая поддержка OpenMP.

Решения на основе OpenMP и Intel® TBB переносимы между ОС Windows, Linux, Mac OS X, Solaris и многими другими операционными системами. Для переноса решения на основе встроенных потоков в другую ОС часто требуется изменение кода. При этом также требуется больше усилий на начальную разработку/ отладку и большие затраты на сопровождение, особенно если необходимо переносить приложения между операционными системами Windows (где обычно используются потоки Windows) и UNIX (где обычно используются потоки POSIX).

Сложность модели параллельной обработки

Подумайте, какие участки кода необходимо обрабатывать параллельно. Используйте OpenMP, если параллелизм в основном предназначен для ограниченных циклов над встроенными типами либо при наличии параллелизма, ориентированного на плоский цикл типа do.

API TBB опирается на обобщенное программирование, поэтому следует использовать его шаблоны параллелизма в том случае, если необходимо работать с пользовательскими пространствами итераций или сложными операциями редукции. Также рассмотрите возможность использования TBB, если необходимо выйти за рамки параллелизма на основе циклов, поскольку этот API предоставляет обобщенные шаблоны параллельной обработки для параллельных циклов while, магистральных моделей потоков данных, параллельной обработки сортировок и префиксов.

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

TBB и OpenMP разработаны для создания многопоточности с целью обеспечения производительности и масштабируемости. Представленные в них структурные элементы специально предназначены для параллельного разбиения масштабируемых данных. Они очень полезны для интенсивных вычислительных нагрузок. Введение параллелизма и достижение хороших показателей производительности при масштабировании значительно усложняется при использовании встроенных потоков. При использовании встроенных потоков для реализации шаблонов/алгоритмов, которые в готовом виде предоставляются в TBB, более вероятно возникновение таких ошибок многопоточности, как состязание потоков и взаимная блокировка. Как отмечалось, в определенных случаях встроенные потоки являются лучшим вариантом, например, при создании многопоточности на основе событий или на основе ввода-вывода.

Сравнение возможностей

Intel® TBB

OpenMP

Threads

Параллелизм на уровне задач

+

+

-

Поддержка декомпозиции данных

+

+

-

Сложные шаблоны параллельной обработки (не циклы)

+

-

-

Широко применимые обобщенные шаблоны параллельной обработки

+

-

-

Поддержка масштабируемого вложенного параллелизма

+

-

-

Динамическое распределение нагрузки

+

+

-

Поддержка привязки потоков к ядрам (affinity)

-

+

+

Статическое распределение нагрузки

-

+

-

Параллельные структуры данных

+

-

-

Масштабируемое средство распределения памяти

+

-

-

Задачи с преобладанием ввода-вывода

-

-

+

Базисные элементы синхронизации на уровне пользователя

+

+

-

Не требуется поддержка компилятора

+

-

+

Поддержка в различных ОС

+

+

-

Ранее были затронуты вопросы, связанные со средой разработки и сложностью модели параллельной обработки, которые следует учитывать при выборе API для реализации многопоточности. Однако как быть в том случае, если и TBB, и OpenMP являются вполне подходящими вариантами? Тогда следует рассмотреть возможности, предлагаемые в этих интерфейсах. Если требуются возможности, которые имеются только в OpenMP, выберите OpenMP. Если требуются возможности, которые имеются только в TBB, используйте TBB. Если необходимые возможности доступны и в TBB, и в OpenMP, рекомендуется учесть затраты на сопровождение: некоторые стили программирования могут лучше подходить для TBB или OpenMP; и TBB, и OpenMP являются переносимыми, однако предъявляют различные требования к средам разработки. TBB и OpenMP могут сосуществовать, однако при этом могут возникнуть проблемы производительности, описанные в разделе "Сосуществование". Поэтому лучше выбрать одну модель, которая охватывает все требования. Если при работе над новым проектом планируется использовать C++, тогда оптимальным выбором будет TBB: TBB разработан для поддержки инкрементного параллелизма, обеспечивая возможность дополнительного распараллеливания без создания ненужных потоков, что могло бы привести к излишней загрузке.

Предполагается, что показатели работы решений на основе Intel® TBB, OpenMP и встроенных потоков сопоставимы (обеспечивают сравнимую производительность) для эквивалентных алгоритмов. Однако значительный объем дополнительного программирования, связанный с API-интерфейсом низкоуровневых встроенных потоков, заставляет отдавать приоритет TBB и OpenMP.

Сосуществование

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

Планировщик задач Intel® TBB является несправедливым (unfair) и не обеспечивает вытеснение (non-preemptive). Поэтому не рекомендуется использовать Intel® TBB для задач, связанных с вводом-выводом. Для таких задач лучше использовать встроенные потоки, которые корректно сосуществуют с компонентами Intel® TBB.

Заключение

Выбор подхода к созданию многопоточности является важной частью процесса проектирования параллельных приложений. Одного решения, которое соответствует всем требованиям и средам, не существует. В некоторых случаях требуется поддержка компилятора, некоторые варианты не являются переносимыми либо не поддерживаются специализированными инструментами анализа многопоточности. Intel® Threading Building Blocks реализует часто используемые шаблоны параллельной обработки, что обеспечивает достаточную среду для более быстрого создания масштабируемых программ, предоставляя параллельные контейнеры данных, базовые элементы синхронизации, параллельные алгоритмы и средства масштабируемого выделения памяти.

Дополнительная информация

  1. «Intel Threading Building Blocks: Разработка параллельных приложений на языке С++ для систем на базе многоядерных процессоров» ("Intel Threading Building Blocks: Outfitting C++ for Multi-core Processor Parallelism"), Джеймс Рейндерс (James Reinders), издательство O'Reilly Media, 2007, ISBN 0596514808.
  2. Веб-страница проекта ПО с открытым исходным кодом: http://www.threadingbuildingblocks.org
  3. Веб-страница продукта: http://www.intel.com/software/products/tbb
  4. Сетевой семинар Dr. Dobb’s "Intel® Threading Building Blocks: разработка масштабируемого ПО для многоядерных систем": http://www.cmpnetseminars.com/TSG/?K=3TW6&Q=417
  5. "Прояснение некоторых аспектов разработки масштабируемых параллельных приложений с использованием обобщенных параллельных алгоритмов в Intel Threading Building Block": http://www.devx.com/cplus/Article/32935
  6. "Обеспечение разработки безопасных, масштабируемых параллельных приложений с использованием параллельных контейнеров в Intel Threading Building Block": http://www.devx.com/cplus/Article/33334
  7. Обзор продукта: Intel Threading Building Blocks: http://www.devx.com/go-parallel/Article/33270
  8. «Революция параллелизма» ("The Concurrency Revolution"), Герб Саттер (Herb Sutter), Dr. Dobb’s 1/19/2005: http://www.ddj.com/dept/cpp/184401916
Для получения подробной информации о возможностях оптимизации компилятора обратитесь к нашему Уведомлению об оптимизации.