Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

[ООП] / Лекции / Lecture_5

.pdf
Скачиваний:
31
Добавлен:
07.02.2016
Размер:
187.65 Кб
Скачать

Лекция 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();

}

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

Соседние файлы в папке Лекции