Коллективные операции обмена сообщениями. Редукция. Примеры
Часто возникает потребность разослать некоторую переменную или массив из одного процессора всем остальным. Каждый программист может написать такую процедуру с использованием операций 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();}
Сурак