>
>
Знакомство с уровнями распараллеливания

Андрей Карпов
Статей: 671

Знакомство с уровнями распараллеливания

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

Распараллеливание на уровне задач

Часто распараллеливание на этом уровне является самым простым и при этом самым эффективным. Такое распараллеливание возможно в тех случаях, когда решаемая задача естественным образом состоит из независимых подзадач, каждую из которых можно решить отдельно. Хорошим примером может быть сжатие аудио-альбома. Каждая запись может обрабатываться отдельно, так как она никак не связана с другими.

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

Другими примерами распараллеливания на этом уровне абстракции является параллельная компиляция файлов в Visual Studio 2008, обработка данных в пакетных режимах.

Как было сказано выше, данный вид распараллеливания прост и в ряде случаев весьма эффективен. Но если мы имеем дело с однородной задачей, то данный вид распараллеливания не применим.

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

Уровень параллелизма данных

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

Данный вид параллелизма широко используется при решении задач численного моделирования. Счётная область представлена в виде ячеек, описывающих состояние среды в соответствующих точках пространства: давление, плотность, процентное соотношение газов, температура и так далее. Количество таких ячеек может быть огромным — миллионы и миллиарды. Каждая из этих ячеек должна быть обработана одним и тем же способом. Здесь модель параллелизма по данным крайне удобна, так как позволяет загрузить каждое ядро, выделив ему определённый набор ячеек. Счётная область разбивается на геометрические объекты, например параллелепипеды, и ячейки, вошедшие в эту область, отдаются на обработку определённому ядру. В математической физике такой тип параллелизма называют геометрическим параллелизмом.

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

В ряде алгоритмов скорость вычисления, где активно протекают процессы, занимает больше времени, чем там, где среда спокойна. Как показано на рисунке, разбив счётную область на неравные части можно получить более равномерную загрузку ядер. Ядра 1, 2 и 3 обрабатывают маленькие области, где движется тело, а ядро 4 обрабатывает большую область, которая ещё не подверглось возмущению. Все это требует дополнительного анализа и создания алгоритма балансировки.

Наградой за такое усложнение является возможность решать задачи длительного движения объектов за приемлемое время расчёта. Примером может служить старт ракеты.

Уровень распараллеливания алгоритмов

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

OpenMP (Open Multi-Processing) — это набор директив компилятора, библиотечных процедур и переменных окружения, которые предназначены для программирования многопоточных приложений на многопроцессорных системах. В OpenMP используется модель параллельного выполнения "ветвление-слияние". Программа OpenMP начинается как единственный поток выполнения, называемый начальным потоком. Когда поток встречает параллельную конструкцию, он создает новую группу потоков, состоящую из себя и некоторого числа дополнительных потоков, и становится главным в новой группе. Все члены новой группы (включая главный поток) выполняют код внутри параллельной конструкции. В конце параллельной конструкции имеется неявный барьер. После параллельной конструкции выполнение пользовательского кода продолжает только главный поток. В параллельный регион могут быть вложены другие параллельные регионы.

За счёт идеи "инкрементального распараллеливания" OpenMP идеально подходит для разработчиков, желающих быстро распараллелить свои вычислительные программы с большими параллельными циклами. Разработчик не создаёт новую параллельную программу, а просто последовательно добавляет в текст последовательной программы OpenMP-директивы.

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

Параллелизм на уровне инструкций

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

Программа представляет собой поток инструкций, выполняемых процессором. Можно изменить порядок этих инструкций, распределить их по группам, которые будут выполняться параллельно, без изменения результата работы всей программы. Это и называется параллелизмом на уровне инструкций. Для реализации данного вида параллелизма в микропроцессорах используется несколько конвейеров команд: такие технологии, как предсказание команд, переименование регистров.

Программист редко заглядывает на этот уровень. Да и в этом нет смысла. Работу по расположению команд в наиболее удобной последовательности для процессора выполняет компилятор. Интерес этот уровень распараллеливания может представлять только для узкой группы специалистов, выжимающие все возможности из SSEx или разработчиков компиляторов.

Вместо заключения

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

  • https://software.intel.com/ru-ru/articles/visualizing-parallel-speedup-with-cilkview/ - Сообщество разработчиков программного обеспечения. Я не сотрудник Intel, но очень рекомендую этот ресурс как член этого сообщества. Очень много интересных статей, записей в блогах и обсуждений, касающихся параллельного программирования.
  • http://www.viva64.com/ru/links/parallel-programming-ru/ - Обзоры статей по параллельному программированию с использованием технологии OpenMP.