我有一个非常简单的 MPI 程序来测试 MPI_Reduce 的行为。我的目标很简单:
~ 首先让每个进程创建一个随机数(范围 1-100)
然后用 mpirun -np 5 <program_name_here>
运行程序
- 有进程 0,求所有 5 个数字的和
- 执行过程 1,求所有 5 个数字的乘积
- 进行过程 2,找出所有 5 个数字中的最大值
- 进行过程 3,求所有 5 个数字的最小值
- 进行过程 4,求所有 5 个数字的按位与
这是我的程序:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <time.h>
int sum = 0;
int product = 0;
int max = 0;
int min = 0;
int bitwiseAnd = 0;
int main ( int argc, char **argv )
{
int my_id, num_procs;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
int num;
srand(time(NULL) * my_id);
num = rand() % 100; //give num the random number
printf("Process #%i: Here is num: %i\n",my_id,num);
if(my_id == 0){
printf("Okay it entered 0\n");
MPI_Reduce(&num, &sum,1,MPI_INT,MPI_SUM, 0, MPI_COMM_WORLD);
}else if(my_id == 1){
printf("Okay it entered 1\n");
MPI_Reduce(&num, &product,1,MPI_INT,MPI_PROD, 0, MPI_COMM_WORLD);
}else if(my_id == 2){
printf("Okay it entered 2\n");
MPI_Reduce(&num, &max,1,MPI_INT,MPI_MAX, 0, MPI_COMM_WORLD);
}else if(my_id == 3){
printf("Okay it entered 3\n");
MPI_Reduce(&num, &min,1,MPI_INT,MPI_MIN, 0, MPI_COMM_WORLD);
}else if(my_id == 4){
printf("Okay it entered 4\n");
MPI_Reduce(&num, &bitwiseAnd,1,MPI_INT,MPI_BAND, 0, MPI_COMM_WORLD);
}
MPI_Barrier(MPI_COMM_WORLD);
if(my_id == 0){
printf("I am process %i and the sum is %i\n",my_id,sum);
printf("I am process %i and the product is %i\n",my_id,product);
printf("I am process %i and the max is %i\n",my_id,max);
printf("I am process %i and the min is %i\n",my_id,min);
printf("I am process %i and the bitwiseAdd is %i\n",my_id,bitwiseAnd);
}
MPI_Finalize();
}
这会产生如下输出:
[blah@blah example]$ mpirun -np 5 all
Process #2: Here is num: 21
Okay it entered 2
Process #4: Here is num: 52
Okay it entered 4
Process #0: Here is num: 83
Okay it entered 0
Process #1: Here is num: 60
Okay it entered 1
Process #3: Here is num: 66
Okay it entered 3
I am process 0 and the sum is 282
I am process 0 and the product is 0
I am process 0 and the max is 0
I am process 0 and the min is 0
I am process 0 and the bitwiseAdd is 0
[blah@blah example]$
为什么进程 0 不从其他进程获取 MPI_Reduce 结果?
最佳答案
我通过实验找出了你的程序出了什么问题,并基于此,我有一个假设来解释为什么它是错误的。
程序的此修改版本执行您期望的操作:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <mpi.h>
int main (int argc, char **argv)
{
int my_id;
int num_procs;
int num;
int sum = 0;
int product = 0;
int max = 0;
int min = 0;
int bitwiseAnd = 0;
int seed = time(0);
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
srand(seed * my_id);
num = rand() % 100;
printf("Process #%i: Here is num: %i\n",my_id,num);
MPI_Reduce(&num, &sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&num, &product, 1, MPI_INT, MPI_PROD, 0, MPI_COMM_WORLD);
MPI_Reduce(&num, &max, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
MPI_Reduce(&num, &min, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD);
MPI_Reduce(&num, &bitwiseAnd, 1, MPI_INT, MPI_BAND, 0, MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
if (my_id == 0) {
printf("The sum is %i\n", sum);
printf("The product is %i\n", product);
printf("The max is %i\n", max);
printf("The min is %i\n", min);
printf("The bitwiseAnd is %i\n", bitwiseAnd);
}
MPI_Finalize();
return 0;
}
我所做的许多更改只是装饰性的。造成差异的变化是,所有进程必须执行所有MPI_Reduce
调用才能计算所有结果。
现在,为什么这很重要?我必须强调,这是一个假设。我不知道。。但符合现有事实的解释是:在我和您的 MPI 实现中,MPI_Reduce
调用中的实际计算仅发生在根进程,但所有其他进程也必须调用 MPI_Reduce 才能发送包含其值的消息。该消息不依赖于操作参数。因此,MPI_SUM 调用偶然做了它应该做的事情,因为对 MPI_Reduce 的其他调用提供了它所需的值。但其他调用根本没有进行任何计算。
如果我的假设是正确的,如果您想让每个计算在不同的进程中执行,您将需要以完全不同的方式构建您的程序。抽象地说,您希望进行全对全广播,以便所有进程都拥有所有数字,然后本地计算总和、乘积等,然后全对-一个将值发送回根。如果我正在阅读http://mpitutorial.com/tutorials/mpi-scatter-gather-and-allgather/#mpi_allgather-and-modification-of-average-program正确的是,MPI_Allgather
是执行全对全广播的函数的名称。
关于c - MPI_Reduce 不将结果传输到根进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36392896/