C 数组的MPI发送数组
好的,我正在尝试通过MPI发送这样的结构C 数组的MPI发送数组,c,mpi,mpich,C,Mpi,Mpich,好的,我正在尝试通过MPI发送这样的结构 struct BColumns { double **B; int offset; }; 如果我只是像这样分配数据 bSet.offset = myRank; bSet.B = (double **) calloc(2, sizeof(double *)); bSet.B[0] = (double *) calloc(1, sizeof(double)); bSet.B[1] = (dou
struct BColumns {
double **B;
int offset;
};
如果我只是像这样分配数据
bSet.offset = myRank;
bSet.B = (double **) calloc(2, sizeof(double *));
bSet.B[0] = (double *) calloc(1, sizeof(double));
bSet.B[1] = (double *) calloc(1, sizeof(double));
bSet.B[0][0] = 1;
bSet.B[1][0] = 2;
if(myRank == 0){
MPI_Send(&bSet,sizeof(struct BColumns), MPI_BYTE, 1, 1, MPI_COMM_WORLD);
}else{
MPI_Recv(&recvBuf, sizeof(struct BColumns), MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status );
}
我假设它不会很好地工作,因为如果我按原样发送这个结构,它将只发送B中的指针,而该指针不指向其他处理器上的任何东西,那么我将如何在MPI中发送这样的数据。最简单的方法是使用单个数组以行/列主顺序存储值,所以它在内存中都是连续的。然后,您只需要定义一个描述结构内存布局的MPI数据类型(许多双精度和一个int)。正如suszterpatt指出的,您确实希望将
B
块分配到一个大块中;不管怎样,这对性能来说可能更好,但对于任何通信来说,这都是必需的,所以您不必到处寻找指针。我认为,不管怎样,你可能必须在不同的发送中发送大小信息,然后在一个数据块中发送数据,尽管你可能会为你发送的每一个数据块创建和删除不同的MPI类型结构。但对每个对象使用多个发送并不困难:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
typedef struct BColumns {
double **B;
int offset;
} bc;
double **alloc2d(int n, int m) {
double *data = malloc(n*m*sizeof(double));
double **array = malloc(n*sizeof(double *));
for (int i=0; i<n; i++) {
array[i] = &(data[i*m]);
}
return array;
}
void free2d(double **array) {
free(array[0]);
free(array);
}
int main(int argc, char **argv) {
const int tag = 13;
int size, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (size < 2) {
fprintf(stderr,"Requires at least two processes.\n");
exit(-1);
}
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == 0) {
int ncols=3, colsize=5;
bc *send;
send = malloc(sizeof(bc));
send->offset = 1;
send->B = alloc2d(ncols, colsize);
for (int i=0; i<ncols; i++)
for (int j=0; j<colsize; j++)
send->B[i][j] = i*j;
const int dest = 1;
MPI_Send(&ncols, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
MPI_Send(&colsize, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
MPI_Send(&(send->offset), 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
MPI_Send(&(send->B[0][0]), ncols*colsize, MPI_DOUBLE, dest, tag,
MPI_COMM_WORLD);
printf("Rank %d: sent structure B\n", rank);
free2d(send->B);
free(send);
}
if (rank == 1) {
MPI_Status status;
const int src=0;
int rncols, rcolsize;
bc *recv;
MPI_Recv(&rncols, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
MPI_Recv(&rcolsize, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
printf("Rank %d: Received: rncols = %d rcolsize=%d\n", rank, rncols, rcolsize);
recv = malloc(sizeof(bc));
recv->B = alloc2d(rncols, rcolsize);
MPI_Recv(&(recv->offset), 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
MPI_Recv(&(recv->B[0][0]), rncols*rcolsize, MPI_DOUBLE, src, tag,
MPI_COMM_WORLD, &status);
printf("Rank %d: Received: offset = %d\n", rank, recv->offset);
for (int i=0; i<rncols; i++) {
printf("%d: Column %d/%d: ", rank, i, rncols);
for (int j=0; j<rcolsize; j++)
printf(" %lf ", recv->B[i][j]);
printf("\n");
}
free2d(recv->B);
free(recv);
}
MPI_Finalize();
return 0;
}
如果您想避免多次发送的延迟(并且如果您事先知道B阵列的最大大小),您可以手动或使用MPI函数调用或数据类型,将该数据整理成一条消息,但是你仍然需要以类似的方式来完成它。那么,如果我没有为这个数组设置一个大小,那么我仍然需要在结构中使用一个指针,并且我动态地分配数组,即使我将它放在行/列主进程中,我仍然会向其他进程传递一个没有任何意义的指针。因此,您不会发送结构本身。相反,发送接收进程可以从中重建相同结构的数据:double和int的数组。原理是一样的,不过您必须巧妙地使用
MPI_Address
函数,并确保double和int在内存中的相对位置不会改变,或者在数据类型更改后重新定义它。或者只是传递多条消息。
$ mpirun -np 3 ./bstruct
Rank 0: sent structure B
Rank 1: Received: rncols = 3 rcolsize=5
Rank 1: Received: offset = 1
1: Column 0/3: 0.000000 0.000000 0.000000 0.000000 0.000000
1: Column 1/3: 0.000000 1.000000 2.000000 3.000000 4.000000
1: Column 2/3: 0.000000 2.000000 4.000000 6.000000 8.000000