Параллельное мышление: три инженера Intel делятся опытом

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

Путь к сердцу параллельных технологий

Для многих программирование связано, прежде всего, с разработкой последовательных приложений. Однако, сегодня программистам, работающим над созданием параллельных приложений, приходится отказываться от традиционного подхода. При разработке последовательного кода можно без труда проследить порядок выполнения программы. Программист точно знает, как осуществляется доступ к данным и их изменение, четко представляет себе все зависимости в коде программы. «При написании параллельного приложения все это можно выкинуть из головы», – уверяет Генри Гэбб, старший инженер Intel Software and Services Group. – «Теперь вам придется учитывать временной фактор. У вас есть множество одновременно выполняющихся инструкций – представьте, насколько сильно это влияет на ваши структуры данных, переменные, алгоритмы. Да практически на все».

В том же ключе высказывается и Тим Маттсон, старший инженер Intel Microprocessor Techology Laboratory. «В вашей программе одновременно возникают и меняются различные состояния исполнения. Изменяются зависимости. А вам приходится все это учитывать». По мнению Тима, именно эта особенность «является ключом к тому, чтобы перестроить свое мышление для понимания механизма работы параллельной программы».

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

«Я не думаю, что переход к приложениям с разделяемой памятью настолько уж сложен, если сравнивать с приложениями с распределенной памятью», добавляет Клэй Бреширс, координатор курсов Intel Academic Community. «Если вы работаете с одним потоком и понимаете, как разделить задачи, не представляет особой сложности добавить другой поток – представьте себе двух рабочих, делящих работу между собой».

Распараллель это

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

Когда распараллеливание программы оправдывает затраченные усилия? Генри предлагает отталкиваться от закона Амдаля и требований заказчиков. «Если я уверен, что могу добиться теоретического прироста скорости», – говорит он, – «и клиенту этого достаточно, то я смотрю на распределение нагрузки. Насколько равномерно параллельная работа может быть распределена между потоками? Если распределение нагрузки корректно, я оцениваю степень модульности. Достаточен ли выделяемый каждому потоку объем работы для того, чтобы оправдать затраты на создание этого потока? Несоответствие любому из указанных критериев может сделать проект непригодным для распараллеливания. Когда все условия соблюдены, можно приступать к работе».

Тим, в свою очередь, полагается на свой богатый опыт в области программирования для научных расчетов. «Что касается задач, с которыми я обычно работаю, я хорошо представляю, что делает программа, где возможен параллелизм и какие участки кода предъявляют наибольшие требования к системным ресурсам. Если я не могу распараллелить такие участки, то продолжать работу уже не имеет смысла».

Хорошим примером может стать алгоритм для трехмерной калибровки глубинной миграции до суммирования (3D prestack depth migration). «Я знаю, что тут будет использоваться множество быстрых преобразований Фурье (FFT)», – поясняет Тим. – «Я знаком с математическими алгоритмами для преобразований Фурье. И я знаю, как будет выглядеть структура данных по мере загрузки и обработки совокупности записей. Таким образом, я могу понять, где мой код необходимо разделять на потоки».

Если вам предстоит работать над незнакомым приложением, точно также необходимо понять принципы работы алгоритма, который предстоит распараллелить. «Кому-то все равно придется с этим разбираться», – считает Клэй. – «Соответственно, если вы представляете себе, что такое параллелизм, то вы ищете в коде независимые операции и рисуете себе картину возможных участков для распараллеливания».

Индивидуальный подход

Нередко разные программисты подходят к написанию параллельных приложений по-своему. Например, Генри предпочитает полагаться на Intel Threading Tools. Тим обычно не пользуется вспомогательными средствами (за исключением Intel Thread Checker).

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

Как только Клэй завершает распараллеливание своего кода и получает его рабочий вариант, он сосредоточивается на оптимизации, преимущественно с помощью таких инструментов, как Intel® Thread Checker, Intel® Thread Profiler и Intel® Cluster Tools.

О пользе параллельных шаблонов

«Запоминать, что и как делают одновременно выполняющиеся потоки, очень трудно», – поясняет Тим, – «поэтому программисты создают более простые и более ограниченные структуры, которые помогают им управлять параллельным приложением. Эти структуры затем могут быть повторно использованы в качестве шаблонов для распараллеливания других задач». Более подробно эта тема рассматривается в книге Тима Маттсона «Шаблоны для параллельного программирования» (Patterns for Parallel Programming).

«Со временем», – продолжает Тим, – «программист накапливает у себя в голове целый каталог всевозможных решений. В теории вычислительных систем они называются шаблонами. По мере того, как опытный программист изучает поставленную перед ним задачу, он получает о ней достаточно информации, чтоб подобрать нужный шаблон для решения какой-либо ее части. Различие между опытным и начинающим программистом заключается в том, что опытный специалист знает больше разнообразных шаблонов».

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

Ловушки параллельного программирования

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

Тим считает, что наибольшим препятствием для разработчика является отсутствие достаточного опыта в том, что он иронически называет «мозговым штурмом» (имея в виду интеллектуальную работу для осмысления задачи и выявления возможностей распараллеливания). «Параллельное программирование – это большой объем знаний, для накопления которого требуется время и практический опыт», – говорит он. – «Программисту необходимо усвоить основные приемы и основные классы алгоритмов, изучить шаблоны, понять причины основных трудностей. Написание кода – это самая простая часть вашей работы. Самое же трудное – разобраться в параллельном алгоритме». Тим рекомендует свою книгу в качестве практического пособия для того, чтобы познакомиться с параллельными шаблонами и научиться их эффективно применять.

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

Путь к мастерству

Как проще всего добиться успеха в сфере параллельного программирования? «Программирование – это искусство», – считает Клэй, – «а параллельное программирование это уже другое искусство. Сначала вы овладеваете его инструментами, потом практикуетесь, и со временем уже интуитивно понимаете, что и как делать».

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

Все три героя нашей публикации сходятся в одном мнении: искусство параллельного программирования лучше всего постигается на практике.

О интервьюируемых

Генри Гэбб (Henry Gabb) – старший инженер Intel Software and Services Group. Занимается параллельными приложениями уже около 15 лет. Генри получил диплом бакалавра по биохимии в Государственном университете Луизианы и ученую степень доктора по молекулярной генетике в Университете Алабамы, Бирмингем, Колледж медицины.

Клэй Бреширс (Clay Breshears) в настоящее время работает координатором курсов Intel Academic Community и специализируется на программировании и обучении в сфере многоядерных процессоров и многопоточных приложений. В 1996 году он получил степень доктора по теории вычислительных систем в Университете Теннесси, Кноксвилль. В рамках своей деятельности он занимается различными аспектами параллельных вычислений уже более 20 лет.

Тимоти Маттсон (Timothy Mattson) – старший инженер Intel Microprocessor Technology Laboratory. Впервые он начал писать параллельные приложения еще в 1985 году, работая научным сотрудником в Калифорнийском технологическом институте в рамках проекта Cosmic Cube (один из первых компьютеров с топологией гиперкуба и поддержкой параллельных вычислений). С тех пор специализируется на применении компьютеров с параллельной архитектурой для решения различных научных задач.

О авторе

Кен Стрэндберг (Ken Strandberg) является автором статей и технических публикаций, семинаров и других материалов для отраслевых изданий, инновационных компаний, работающих в сфере новейших технологий, крупнейших предприятий, входящих в рейтинг Fortune 100, и международных корпораций. Написать Кену Стрендбергу можно по адресу ken@kenstrandberg.com.

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