Вы находитесь на странице: 1из 4

Лекция 5

Параллельное программирование
Для эффективного использования высокопроизводительных вычислительных систем
необходимо уметь их эффективно программировать. Одного языка программирования, пусть
даже самого современного, уже не достаточно для программирования многопроцессорных
или многомашинных комплексов, если они должны выполнять одну программу. Необходимо
программировать и обмены данными между процессами одной задачи, выполняющимися на
разных процессорах. Кроме того, возникнут вопросы контроля правильности обмена, взаим-
ной синхронизации процессов, отладки и верификации. Таким образом, мы приходим к по-
нятию параллельной программы, программы, которая состоит из нескольких программ, в
общем случае содержащих различный код, и которая решает одну задачу.
Для создания параллельных программ разработано и продолжает разрабатываться
множество языков и технологий параллельного программирования. Назовем лишь несколь-
ко: Ada, ATLAS, HPF, HPC, Linda, Modula-3, MPI, mpC, OpenMP, Occam, P4, Parallaxis, PVM
и др. В процессе создания языков параллельного программирования выработано несколько
подходов к организации распараллеливания программ. Рассмотрим некоторые. Наиболее
простой и известный подход связан с построением системы параллельного программирова-
ния на основе существующего языка для программирования последовательной машины. На-
пример язык HPF – High Perfomance Fortran. В нем использована очень привлекательная идея
включения в программу "подсказок" для компилятора в виде комментариев. Как известно,
комментарий в языке Fortran обозначается символом C. Операторы организации параллель-
ных вычислений, например обмена, обозначаются в HPF с помощью двух символов C. Таким
образом, программу можно компилировать и с помощью обычного компилятора: все что
начинается с символа C является для него комментарием, а для компилятора, снабженного
средствами распараллеливания, операторы, начинающиеся с двойного CC являются операто-
рами для компиляции параллельных операторов.
Другой подход – включение в обычный язык программирования специальных функций
из специально созданных для параллельного программирования библиотек. Мы рассмотрим
несколько наиболее популярных технологий параллельного программирования.
Для программирования компьютеров с разделяемой памятью, т.е. SMP-компьютеров
используется система OpenMP. Это стандарт, разработанный для языков Fortran, C, C++ и
многих операционных платформ UNIX, Linux, Windows NT. Вся программа разбивается на
последовательные и параллельные участки. Последовательные участки реализуются основ-
ным потоком или нитью (thread), а параллельные – дочерними потоками. Все переменные
разделяются на общие и локальные, причем, локальные переменные являются доступными
только внутри конкретного потока, а общие - доступны для всех потоков. Понятно, что под-
ход многопоточности очень удобен для систем с разделяемой памятью. Области для парал-
лельного выполнения выделяются с помощью директив, начало которых обозначаются с по-
мощью символа комментария, о которых говорилось выше. Например:
C$OMP PARALLEL
код для параллельного выполнения
C$OMP END PARALLEL

Внутри параллельного блока порождается столько потоков, сколько указал программист пе-
ред запуском программы. В конце параллельного блока все потоки синхронизируются, т.е.
происходит ожидание завершения работы всех потоков и их уничтожение. Число потоков
внутри потоков можно изменять с помощью специальных операторов. Кроме того, сущест-
вует множество различных операторов для управления работой потоков и выполнения
различных коллективных операций. Для более подробного ознакомления с технологией
OpenMP можно рекомендовать сайт http://www.openmp.org. В настоящее время эта техноло-
2

гия используется, как мы уже отмечали, для организации программирования SMP-


компьютеров, а также для организации работы узлов кластеров, которые обычно строятся с
использованием двух или четырех SMP-процессоров.
Если технология OpenMP базируется на потоках и это естественно для SMP-
процессоров, то для кластеров и MPP-компьютеров, где память является распределенной и
взаимодействие между процессорами осуществляется с помощью специальных коммуника-
ционных сред, более подходящим является подход, основанный на передаче сообщений. Со-
общение представляет собой посылку от одного процессора к другому, в которой содержатся
данные и служебная информация. На этом подходе базируются два очень распространенных
и похожих стандарта (технологии) MPI – Message Passing Interface и PVM – Parallel Virtual
Machine.
Более подробно мы будем изучать систему MPI, и в начале рассмотрим общие понятия
технологии передачи сообщений. Предполагается, что в нашем распоряжении имеется па-
раллельный компьютер с распределенной памятью, а связь между процессорами осуществ-
ляется с помощью некоторой коммуникационной средой. Отметим, что это может быть даже
компьютер с одним процессором. В этом случае мы говорим, что организуется работа не-
скольких независимых процессов и обмен между ними также организуется некоторым ком-
муникатором. Кстати, именно в таком режиме осуществляется первоначальная отладка па-
раллельной программы. Части параллельной программы можно называть и подзадачами.
Пересылка сообщений между процессами, или подзадачами, или процессорами выпол-
няется путем вызова специальных функций. Программист в общем случае может не интере-
соваться физическим характером коммуникационной среды, он лишь вызывает функции пе-
редачи и приема в подзадачах.
Параллельная программа может состоять из одинаковых для всех подзадач подпро-
грамм. В этом случае схема программирования называется SPMD (Single Program Multiple
Data). Параллельная программа может состоять и из различных для каждой подзадачи под-
программ и схема программирования называется MPMD (Multiple Program Multiple Data).
Посылку сообщения можно представить в виде конверта, который содержит в себе
данные, а сам конверт имеет такие атрибуты, как адрес отправителя, адрес получателя, но-
мер или идентификатор сообщения и некоторые другие.
Все сообщения можно разделить на двухточечные и коллективные. Двухточечные со-
общения имеют один процесс-отправитель сообщения и один процесс-получатель.
Коллективные сообщения могут иметь характеры: один-всем, все-одному, все-всем.
Для дальнейшего изложения основ параллельного программирования мы будем ис-
пользовать понятия стандарта MPI, причем, его множество функции будем изучать по мере
надобности.
Стандарт MPI (Message Passing Interface) был разработан в 1994 году на основе многих
ранее существовавших проектов и систем программирования параллельних систем и в на-
стоящее время имеет версию 1.1. В 1998 году разработан более усовершенствованный стан-
дарт MPI-2, однако он до сих пор не получил широкого распространения [2]. На основе стан-
дарта MPI разработано множество реализаций программного обеспечения для языков C и
Fortran, которые используются для многих суперкомпьютеров и кластеров. Эти реализации
стали настолько популярны, что их часто помещают в дистрибутивы ОС Linux. Мы будем
использовать одну из реализаций стандарта в виде библиотеки mpich версии 1.2.4. Аргон-
ской национальной лаборатории США. Дистрибутив библиотеки является некоммерческим и
распространяется бесплатно.
Рассмотрим некоторые основные положения и понятия стандарта MPI:
1. Параллельная программа представляет собой нескольких ветвей, или процессов,
или задач, которые выполняются одновременно;
2. Разные процессы могут выполняться как на разных процессорах, так и на одном и
том же - для программы это роли не играет, поскольку в обоих случаях механизм
обмена данными одинаков;
Высокопроизводительные вычислительные системы и параллельное программирование. Кудерметов Р.К.
3

3. Процессы обмениваются друг с другом данными в виде сообщений. Сообщения


имеют уникальные номера (идентификаторы), которые позволяют программе и
библиотеке связи отличать их друг от друга;
4. Для совместного проведения тех или иных расчетов процессы внутри приложения
объединяются в группы или области взаимодействия. Внутри области взаимодейст-
вия процессы могут обмениваться сообщениями. Для каждой области взаимодейст-
вия создается специальная информационная структура, которая называется комму-
никатором;
5. Каждый процесс внутри группы имеет свой номер. Номера в группе начинаются с
нуля;
6. Для одной области связи может существовать несколько коммуникаторов;
7. Один коммуникатор создается библиотекой MPI автоматически. Он описывает
стартовую область связи, объединяющую все процессы приложения и его иденти-
фикатор MPI_COMM_WORLD.

Среди множества функций библиотеки стандарта MPI можно выделить несколько ос-
новных функций, с помощью которых организуется работа параллельной программы.
Одной из первых функций в программе должна быть функция инициализация библио-
теки MPI MPI_Init(&argc,&argv), которая получает адреса аргументов от функции
main(), которая, в свою очередь, получает из операционной системы. Эти аргументы хранят
параметры командной строки. После вызова функции становятся доступными другие функ-
ции библиотеки MPI.
Для завершения работы параллельной программы используется функция
MPI_Finalize(), после которой уже нельзя использовать функции библиотеки MPI.
Для организации работы программы часто необходимо бывает знать число процессов
или процессоров задействованных внутри коммуникатора и номер данного процесса. Для
этого используются функции:
MPI_Comm_size(comm,&size);
MPI_Comm_rank(comm,&rank);

В этих функциях параметр comm – идентификатор коммуникатора, size – число про-


цессов в коммуникаторе, rank – номер данного процесса в коммуникаторе.
Две наиболее употребительные функции обмена:
int MPI_Send(buf,count,datatype,dest,tag,comm);
int MPI_Recv(buf,count,datatype,source,tag,comm,status),

где void *buf - адрес буфера, т.е. начальный адрес буфера приёма (передачи). Каждый
процесс имеет собственный наборы данных и собственный буфер приема (передачи), поэто-
му адреса буферов каждого из процессов отличаются друг от друга;
int count - размер буфера в количестве ячеек (не в байтах) типа datatype. Для функции
передачи MPI_Send() указывается, сколько ячеек требуется передать, а для функции приема
MPI_Recv() - максимальная емкость приемного буфера. Если фактическая длина пришед-
шего сообщения меньше - последние ячейки буфера не заполняются, если больше - произой-
дет ошибка времени выполнения;
MPI_Datatype datatype - тип ячеек буфера. Функции MPI_Send() и MPI_Recv() опери-
руют массивами однотипных данных. Для описания базовых типов языка С в MPI определе-
ны константы MPI_INT, MPI_CHAR, MPI_DOUBLE и др., имеющие тип MPI_Datatype. Их
названия образуются префиксом MPI_ и именем соответствующего типа (int, char,
double, ...), записанным заглавными буквами. Пользователь может зарегистрировать (опре-
делить) в MPI-приложении свои собственные типы данных, например структуры, после чего
функции MPI смогут обрабатывать их также как и базовые типы;

Высокопроизводительные вычислительные системы и параллельное программирование. Кудерметов Р.К.


4

int dest (source) - номер процесса приемника (источника), с которым происходит обмен
данными;
int tag - идентификатор сообщения, с помощью которого одно сообщение отличается от
другого. Идентификатор сообщения - это целое число от 0 до 32767, которое назначается
пользователем. Важно, чтобы отправленное сообщение с назначенным номером, было при-
нято с таким же номером;
MPI_Comm comm - описатель области связи (коммуникатор);
MPI_Status *status - статус завершения приема. По адресу status содержится инфор-
мация о принятом сообщении, в частности, его идентификатор, номер процесса-передатчика,
код завершения и количество фактически принятых данных.
Пользуясь рассмотренными функциями, напишем простейшую параллельную про-
грамму, которая передает сообщение в виде строки символов из одного процесса в другой.
#include <stdio.h>
#include <string.h>
#include "mpi.h"

int main(int argc,char *argv[])


{
int myrank,size;
char message[25];
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
fprintf(stdout,"I'm %d from %d\n",myrank,size);
if(myrank==1)
{
strcpy(message,"First parallel program");
MPI_Send(message,25,MPI_CHAR,0,100,MPI_COMM_WORLD);
}
if(myrank==0)
{
MPI_Recv(message,25,MPI_CHAR,1,100, MPI_COMM_WORLD,&status);
printf("%s",message);
}
MPI_Finalize();
}

Высокопроизводительные вычислительные системы и параллельное программирование. Кудерметов Р.К.

Вам также может понравиться