Это распространенный источник путаницы для людей, плохо знакомых с MPI. Вы не используете MPI_Recv()
для получения данных, отправленных с помощью трансляции; вы используете MPI_Bcast()
.
Например, что вы хотите, это:
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv) {
int rank;
int buf;
const int root=0;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(rank == root) {
buf = 777;
}
printf("[%d]: Before Bcast, buf is %d\n", rank, buf);
/* everyone calls bcast, data is taken from root and ends up in everyone's buf */
MPI_Bcast(&buf, 1, MPI_INT, root, MPI_COMM_WORLD);
printf("[%d]: After Bcast, buf is %d\n", rank, buf);
MPI_Finalize();
return 0;
}
Для коллективной связи MPI, каждый должен участвовать; каждый должен позвонить в Bcast, или в Allreduce, или как там у вас. (Вот почему в подпрограмме Bcast есть параметр, который задает «root» или того, кто выполняет отправку; если бы только отправитель назывался bcast, это вам не понадобилось бы.) Все вызывают трансляцию, включая получателей; Получатели не просто отправляют получение.
Причина этого заключается в том, что коллективные операции могут вовлекать всех в общение, поэтому вы указываете, что вы хотите, чтобы произошло (каждый получает данные одного процесса), а не как это происходит (например, корневой процессор зацикливается на всех других рангах и отправляет), так что есть возможности для оптимизации шаблонов связи (например, иерархическая связь на основе дерева, которая выполняет log(P)
шагов вместо P
шагов для процессов P).