【问题标题】:How to convert MPI_Reduce into MPI_Send and MPI_Recv?如何将 MPI_Reduce 转换为 MPI_Send 和 MPI_Recv?
【发布时间】:2021-05-07 23:50:53
【问题描述】:

我正在开发一个使用 MPI_Send() 和 MPI_Recv() 而不是 MPI_Reduce() 的并行处理程序。我知道 MPI_Send() 需要从每个处理器发送一个值到根处理器,即 0,而 MPI_Recv() 需要从每个处理器接收所有值。

我不断收到错误消息,即 Send 中的值不会发送到接收端,从而使最终值为 0。 MPI_Reduce() 函数仍在代码中,但已注释掉以查看需要替换的内容。有人可以帮忙吗?

#include "mpi.h"
#include <stdio.h>
#include <math.h>
 
int main( int argc, char *argv[])
{
    int n, i;
    double PI25DT = 3.141592653589793238462643;
    double pi, h, sum, x;
 
    int numprocs, myid;
    double startTime, endTime;
 
    /* Initialize MPI and get number of processes and my number or rank*/
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);
 
    /* Processor zero sets the number of intervals and starts its clock*/
    if (myid==0) {
       n=600000000;
       startTime=MPI_Wtime();
       for (int i = 0; i < numprocs; i++) {
           if (i != myid) {
               MPI_Send(&n, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
           }
       }
    } 
    else {
        MPI_Recv(&n, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    }
 
    /* Calculate the width of intervals */
    h   = 1.0 / (double) n;
 
    /* Initialize sum */
    sum = 0.0;
    /* Step over each inteval I own */
    for (i = myid+1; i <= n; i += numprocs) {
        /* Calculate midpoint of interval */
        x = h * ((double)i - 0.5);
        /* Add rectangle's area = height*width = f(x)*h */
        sum += (4.0/(1.0+x*x))*h;
    }
    /* Get sum total on processor zero */
    //MPI_Reduce(&sum,&pi,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);
    double value = 0;
    if (myid != 0) {
            MPI_Send(&sum, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
    }
    else {
        for (int i = 1; i < numprocs; i++) {
            MPI_Recv(&value, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            pi += value;
            }
    }
    
    /* Print approximate value of pi and runtime*/
    if (myid==0) {
       printf("pi is approximately %.16f, Error is %e\n",
                       pi, fabs(pi - PI25DT));
       endTime=MPI_Wtime();
       printf("runtime is=%.16f",endTime-startTime);
    }
    MPI_Finalize();
    return 0;
}

【问题讨论】:

    标签: c parallel-processing mpi


    【解决方案1】:

    您正在使用MPI_INT 发送double 类型的值:

    if (myid != 0) {
      MPI_Send(&sum, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
      //                ^^^^^^^
    }
    

    int 长 4 个字节; double 是 8 个字节长。虽然接收操作成功,但它不能构造一个类型为MPI_DOUBLE 的值,只给定消息中的 4 个字节,因此它不会向value 写入任何内容,它仍然是0.0。事实上,如果你更换:

    MPI_Recv(&value, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    

    MPI_Status status;
    int count;
    
    MPI_Recv(&value, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &status);
    MPI_Get_count(&status, MPI_DOUBLE, &count);
    if (count == MPI_UNDEFINED) {
      printf("Short message received\n");
      MPI_Abort(MPI_COMM_WORLD, 0);
    }
    

    你的程序将中止,表明条件语句的主体由于MPI_Get_count()count中返回MPI_UNDEFINED而被执行,这表明接收到的消息的长度不是长度的整数倍MPI_DOUBLE.

    另外,pi 必须在接收循环之前显式初始化为 sum,否则由于以下任一错误,您将得到错误的 pi 值:

    • pi 未初始化并具有任意初始值,并且
    • rank 0 的贡献不会添加到最终结果中。

    【讨论】:

      猜你喜欢
      • 2014-04-17
      • 2011-11-11
      • 2017-10-25
      • 2021-05-09
      • 2011-01-24
      • 2014-01-25
      • 2016-04-22
      • 2015-05-14
      • 1970-01-01
      相关资源
      最近更新 更多