Коллективные операции обмена сообщениями. Редукция. Примеры

Часто возникает потребность разослать некоторую переменную или массив из одного процессора всем остальным. Каждый программист может написать такую процедуру с использованием операций Send/Recv, однако гораздо удобнее воспользоваться коллективной операцией MPI_Bcast. Причем гарантировано, что эта операция будет выполняться гораздо эффективнее, поскольку MPI-функция реализована с использованием внутренних возможностей коммуникационной среды.

Широковещательная рассылка данных выполняется с помощью функции MPI_Bcast. Процесс с номером root рассылает сообщение из своего буфера передачи всем процессам области связи коммуникатора comm.

int MPI_Bcast(void* buffer, int count, MPI_Datatype datatype, int root,MPI_Comm comm )

buffer - адрес начала расположения в памяти рассылаемых данных; count - число посылаемых элементов; datatype- тип посылаемых элементов; root - номер процесса-отправителя; comm-коммуникатор.

После завершения подпрограммы каждый процесс в области связи коммуникатора comm, включая и самого отправителя, получит копию сообщения от процесса-отправителя root. На Рис. 4.1 представлена графическая интерпретация операции Bcast. Пример использования функции MPI_Bcast.

...

IF ( MYID .EQ. 0 ) THEN

PRINT *, 'ВВЕДИТЕ ПАРАМЕТР N : '

READ *, N

END IF

CALL MPI_BCAST(N, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, IERR)

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

В MPI глобальные операции редукции представлены в нескольких вариантах: 1) с сохранением результата в адресном пространстве одного процесса (MPI_Reduce). 2) в адресном пространстве всех процессов (MPI_Allreduce). 3) префиксная операция редукции, которая в качестве результата операции возвращает вектор. i-я компонента этого вектора является результатом редукции первых i компонент распределенного вектора (MPI_Scan). 4) совмещенная операция Reduce/Scatter (MPI_Reduce_scatter).

Покажем на примере ф-ции MPI_Reduce, которая выполняется следующим образом. Операция глобальной редукции, указанная параметром op, выполняется над первыми элементами входного буфера, и результат посылается в первый элемент буфера приема процесса root. Затем то же самое делается для вторых элементов буфера и т.д.

int MPI_Reduce(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)

sendbuf - адрес начала входного буфера; recvbuf -адрес начала буфера результатов (используется только в процессе-получателе root); count-число элементов во входном буфере; datatype-тип элементов во входном буфере; op-операция, по которой выполняется редукция; root-номер процесса-получателя результата операции; comm -коммуникатор.

 

 

Напишите программу параллельного скалярного умножения векторов.

int main(int argc,char **argv)

{

int size,rank,i,n=6;

float *a,*b;

a=new float[n];

b=new float[n];

for(i=0;i<n;i++)

{

a[i]=i+1;

b[i]=i+1;

}

MPI_Status status;

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD,&rank);

MPI_Comm_size(MPI_COMM_WORLD,&size);

float f=0,s=0,s1=0;

int nachalo,konec,shag;

shag=n/(size-1);

if(rank!=size-1)

{

nachalo=rank*shag;

konec=rank*shag+shag;

for(i=nachalo;i<konec;i++)

s=s+a[i]*b[i];

MPI_Send(&s,1,MPI_FLOAT,size-1,1,MPI_COMM_WORLD);

}

if(rank==size-1){

for(i=0;i<size-1;i++)

{ MPI_Recv(&s,1,MPI_FLOAT,i,1,MPI_COMM_WORLD,&status);

f=f+s; }

printf("%f\n",f);

}

MPI_Finalize();}

 

Сурак