繁体   English   中英

使用MPI发送和接收派生数据类型

[英]Send and Receive derived Datatypes with MPI

我想以最简单的方式将NXN矩阵的反对角元素从根进程发送到另一个进程。 可悲的是,由于计算节点已关闭,目前我无法测试我的代码。 有人可以检查我的简单代码吗?

我不确定我是否正确发送了A的反诊断元素。 反对角元素是否会降落在接收缓冲区B中?

#include "mpi.h"
#include <stdio.h>

int main(int argc, char** argv){

MPI_Init(&argc,&argv);
int size, rank;

MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);

int N=4;
double A[N][N];
double B[N];
MPI_Datatype antidiag;

int* blockleng=(int*)malloc(N*sizeof(int));
int* displace=(int*)malloc(N*sizeof(int));

for(int i=0; i<N; ++i){
    blockleng[i]=1;
    displace[i] = (i+1)*(N-1);
}

MPI_Type_indexed(N,blockleng,displace, MPI_DOUBLE,antidiag);
MPI_Type_commit(&antidiag);
MPI_Status status;

if(rank==0){
    A= {
            {1.0,5.0,9.0,13.0},
            {2.0,6.0,10.5,14.5},
            {3.0,7.2,11.0,15.0},
            {4.0,8.0,12.0,16.0}
    };


    MPI_Send(A,1,antidiag,1,100,MPI_COMM_WORLD);

}
if(rank==1){
    MPI_Recv(B,1,antidiag,0,100,MPI_COMM_WORLD,status);
}

MPI_Type_free(&antidiag);

MPI_Finalize();
return 0;
}

您的程序中有几个问题。 而不是发布整个程序,我将重点讨论这些问题。

  1. 循环内部的变量声明从C99开始一直保持。 如果您需要使用较旧的标准,这就是循环的样子,

     int i, j; for(i=0; i<N; ++i){ blockleng[i]=1; displace[i] = (i+1)*(N-1); } 
  2. 使用MPI_Type_indexed创建MPI数据类型时, MPI_Type_indexed将最后一个参数(新类型)作为指针/句柄传递:

     MPI_Type_indexed(N, blockleng, displace, MPI_DOUBLE, &antidiag); 
  3. 您将值分配给矩阵A的方式仅在与声明结合的初始化过程中才能实现,更多信息请参见 当然,您可以分别针对等级0和其他等级执行此操作,但是您也可以仅从等级0的文件中读取矩阵数据,

     char* file_in = "matrix_A.txt"; FILE *fpi; fpi=fopen(file_in, "r"); for (i=0; i<N; i++) for (j=0; j<N; j++) if (!fscanf(fpi, "%lf", &A[i][j])) break; 

    作为if(rank==0){块的一部分。 您还可以使矩阵文件名成为命令行参数,这将为您提供更大的灵活性。 那时,您还希望将N作为命令行参数,以能够定义您正在读取的矩阵的大小。 本示例中使用的文件具有简单的结构,

     1.0 5.0 9.0 13.0 2.0 6.0 10.5 14.5 3.0 7.2 11.0 15.0 4.0 8.0 12.0 16.0 
  4. 同一块中的send部分仅发送到一个等级1的等级。如果我正确理解了您的问题,则希望将对角线发送给等级0的所有其他等级,这需要以下循环,

     for (i=1; i<size; i++) MPI_Send(A, 1, antidiag, i, 100, MPI_COMM_WORLD); 
  5. 同样,接收部分应保持除0以外的所有等级,

     else{ MPI_Recv(B, N, MPI_DOUBLE, 0, 100, MPI_COMM_WORLD, &status); } 

    请注意,这里还有其他更正-您是在N大小的缓冲区/数组B中接收数据,而不是在NxN矩阵A中接收数据atidiag是为矩阵A(或N * N元素1D缓冲区)创建的类型这种情况)-它不适用于N个元素缓冲区B。因此,您需要更改MPI_Recv以期望/检索MPI_DOUBLE类型的N个元素。 这是一项很好的功能,因为它使您可以将数据接收到与发送数据不同的结构数组中。 您还需要传递一个指向status的指针,因此是&status

最后,您可以打印结果,

 if (rank != 0){
    printf("Rank %d:\n", rank);
    for (i=0; i<N; i++)
      printf("%.2lf ", B[i]);
  }
  printf("\n\n");

请注意,MPI打印到stout打印不是基于等级编号排序的,更重要的是,在打印期间,等级可能会相互干扰。 刷新stdout可能会有所帮助,但更好的选择是写入文件。 在这种情况下,在我的系统上,输出将按原样打印。 经过多达6个过程的测试。

后记-通常在1个进程发送给所有其他进程的情况下,您应该考虑使用MPI_Bcast类的集体通信功能。 这些功能经过高度优化,在专门处理的情况下性能优于Send \\ Recv。现在,使用Bcast您需要将接收到的对角线实际存储在所有等级的A矩阵中,然后将其复制到等级的数组/缓冲区B中。而不是0。这会增加几个步骤,因此我将其保留在您的帖子中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM