Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MPI_Reduce不将结果传输到根进程_C_Mpi - Fatal编程技术网

MPI_Reduce不将结果传输到根进程

MPI_Reduce不将结果传输到根进程,c,mpi,C,Mpi,我有一个非常简单的MPI程序来测试MPI_Reduce的行为。我的目标很简单: ~首先让每个进程创建一个随机数(范围1-100) 然后使用mpirun-np5运行程序 让进程0,找到所有5个数字的总和 进行过程1,找出所有5个数字的乘积 进行过程2,找出所有5个数字的最大值 进行过程3,找出所有5个数字的最小值 在进程4中,找到所有5个数字的按位and 这是我的节目: #include <stdio.h> #include <stdlib.h> #include &l

我有一个非常简单的MPI程序来测试MPI_Reduce的行为。我的目标很简单:

~首先让每个进程创建一个随机数(范围1-100) 然后使用
mpirun-np5运行程序

  • 让进程0,找到所有5个数字的总和
  • 进行过程1,找出所有5个数字的乘积
  • 进行过程2,找出所有5个数字的最大值
  • 进行过程3,找出所有5个数字的最小值
  • 在进程4中,找到所有5个数字的按位and
这是我的节目:

#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();
}

为什么进程0没有从其他进程获取MPI\u 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;
}
#包括
#包括
#包括
#包括
int main(int argc,字符**argv)
{
输入我的id;
int num_进程;
int-num;
整数和=0;
int乘积=0;
int max=0;
int min=0;
int按位AND=0;
int seed=时间(0);
MPI_Init(&argc,&argv);
MPI通信等级(MPI通信世界和我的id);
MPI_通信大小(MPI_通信世界和数量进程);
srand(seed*my_id);
num=rand()%100;
printf(“进程#%i:这里是num:%i\n”,我的#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_屏障(MPI_通信世界);
if(my_id==0){
printf(“总和为%i\n”,总和);
printf(“产品是%i\n”,产品);
printf(“最大值为%i\n”,最大值);
printf(“最小值为%i\n”,最小值);
printf(“位与为%i\n”,位与);
}
MPI_Finalize();
返回0;
}
我所做的许多改变只是表面上的。造成差异的变化是,所有进程都必须执行所有的
MPI\u Reduce
调用,以便计算所有结果

现在,这有什么关系?我必须强调,这是一种假设。我不知道。但符合现有事实的解释是:在我和您的MPI实现中,
MPI_Reduce
调用中的实际计算只发生在根进程上,但所有其他进程也必须调用MPI_Reduce才能发送带有其值的消息。该消息不依赖于操作参数。因此,MPI_SUM调用意外地完成了它应该做的事情,因为其他对MPI_Reduce的调用提供了它需要的值。但其他调用都没有进行任何计算


如果我的假设是正确的,那么如果你想在不同的过程中进行每一次计算,你就需要以不同的方式构造你的程序。抽象地说,您需要一个all-to-all广播,以便所有进程都有所有的数字,然后本地计算总和、乘积等,然后all-to-one将值发送回根。如果我读得正确,
MPI_Allgather
是对所有广播执行所有操作的函数的名称。

zwol的回答基本正确,但我想重申他的假设:

MPI\u Reduce
是一个集合操作,必须由通信器参数的所有成员调用。在
MPI\u COMM\u WORLD
的情况下,这意味着应用程序中的所有初始等级

在这里也很有用:

所有组成员使用相同的参数调用该例程 对于count、datatype、op、root和comm。因此,所有进程都提供 相同长度的输入缓冲区[…]

重要的是要理解,根并不是做所有计算的那个。该操作以分布式方式完成,通常使用树算法。这意味着只需执行对数数量的时间步,这比仅将所有数据收集到根并在那里执行操作要高效得多,尤其是对于大量列组

因此,如果希望得到排名为0的结果,确实必须无条件运行代码,如下所示:

[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]$
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);

如果需要不同级别的结果,可以相应地更改
root
参数。如果您希望结果在所有级别都可用,请改用
MPI\u Allreduce

这是一种暗中操作,但是否可能正在等待,但是每个进程都有自己的输出变量副本,因此进程0无法看到所有其他进程的结果?但是如果它正在等待,为什么打印语句会在打印结果之后打印?我认为这是stdio缓冲混淆了问题。这些是最后处理1-4打印的内容,并且您没有在这些字符串的末尾加上\n(这会触发刷新,因为输出是到终端的),因此直到处理1-4退出(执行隐式刷新)它们才会被打印。啊。这是有道理的。我没有想到这一点。从文档(很少有)来看,似乎MPI_Reduce应该简单地将结果存储在作为param传递的全局变量中。我假设我的变量不是全局变量,你对单独副本的看法正确吗?全局必须在主..之上吗?关于缓冲区刷新,您是正确的。在那些printf上加上“\n”使它们在打印结果之前打印,如果我从
my_id==1
打印
product
,它仍然等于0。因此,它从不使用Reduce调用设置其他变量。据我所知,MPI_Reduce方法应该将结果返回到根进程。至于实际的实现,它确实令人困惑。感谢您的解决方案!这确实有效。你的假设的一部分是“你必须打电话。”