c - MPI_Reduce 不将结果传输到根进程

标签 c mpi

我有一个非常简单的 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/

相关文章:

c++ - 为什么我的 fortran 例程将不正确的值传递给我的 C++ 函数?

c - 什么可能导致死循环,由 linux 内核中的 print "Dead loop on virtual device "指示?

c - 使用接口(interface)的质数

c - 结构体数组中每个元素的 mpi 通信器

c - 了解 MPI 错误

c++ - MPI 发送传递指针指针 c++

c++ - 指针被释放

c - "error: (1098) conflicting declarations"当函数类型改变时

c - 在 C 中打印特定数据类型的值?

c - 如何使用树莓派的i2c程序配置霍尔效应传感器(si7210)(C语言)