我需要从根节点向所有处理器传递一个整数数组的数组(基本上是一个二维数组)。我正在使用C程序中的MPI。如何声明MPI数据类型以用于二维数组,以及如何发送消息(应该使用广播还是散射)。
你需要使用Broadcast,因为你想要将相同的消息副本发送到每个进程。Scatter会将消息分解并在进程之间分配块。
至于如何发送数据:HIndexed数据类型适合你。
假设你的二维数组定义如下:
int N; // number of arrays (first dimension)
int sizes[N]; // number of elements in each array (second dimensions)
int* arrays[N]; // pointers to the start of each array
首先,您需要计算每个数组的起始地址相对于数据类型的起始地址的位移量,这可以是第一个数组的起始地址,以方便处理:
MPI_Aint base;
MPI_Address(arrays[0], &base);
MPI_Aint* displacements = new int[N];
for (int i=0; i<N; ++i)
{
MPI_Address(arrays[i], &displacements[i]);
displacements[i] -= base;
}
MPI_Datatype newType;
MPI_Type_hindexed(N, sizes, displacements, MPI_INTEGER, &newType);
MPI_Type_commit(&newType);
这个定义将创建一个数据类型,其中包含所有数组按顺序打包在一起。完成后,您只需将数据作为此类型的单个对象发送:
MPI_Bcast(arrays, 1, newType, root, comm); // 'root' and 'comm' is whatever you need
然而,你还没有完成。接收方进程需要知道要发送的数组的大小:如果这些信息在编译时不可用,则必须首先发送包含该数据的单独消息(int数组)。如果在接收方进程上定义了类似上述的N
、sizes
和arrays
,并已分配足够的空间来填充这些数组,则所有接收方进程只需要定义相同的数据类型(与发送方完全相同的代码),然后将发送方的消息作为该类型的单个实例进行接收:
MPI_Bcast(arrays, 1, newType, root, comm); // 'root' and 'comm' must have the same value as in the sender's code
看,现在所有的进程都有你的数组的副本了。
当然,如果你的二维数组的第二个维度固定为某个值M
,那么事情会变得更加容易。在这种情况下,最简单的解决方案是将其存储在一个单独的int[N*M]
数组中:C++将保证它是连续的内存,因此您可以在不定义自定义数据类型的情况下进行广播,例如:
MPI_Bcast(arrays, N*M, MPI_INTEGER, root, comm);
displacements
数组以元素数量给出,而在HIndexed中是以字节数给出(H代表异构)。如果你要使用Indexed,则displacements
中给出的值必须除以sizeof(int)
。但是,我不确定在堆上任意位置定义的整数数组是否保证在C++中“排列”到整数极限,无论如何,HIndexed版本具有(稍微)少一些代码并产生相同的结果。MPI_Bcast(&buf, numRows*numCols, MPI_INT, root, MPI_COMM_WORLD)
where
&buf
是数组中第一个元素的地址
numRows*numCols
当然是二维数组中元素的数量
MPI_INT
是(可能)要使用的内置数据类型
root
是广播数组的进程的排名
MPI_COMM_WORLD
是通常的默认通信器,如果需要可以更改
不要忘记广播是一种集体操作,所有进程都会进行相同的调用。
如果您的数组不是连续的,请再次发布一些示例数组大小,我们将找出如何定义MPI数据类型。
MPI_Send(tempmat,16,MPI_INT,0,0,MPI_COMM_WORLD);
MPI_Recv(resultmaster,16,MPI_INT,MPI_ANY_SOURCE , 0, MPI_COMM_WORLD, &stat);
当使用上述API时,我只得到矩阵的第一行。
你的二维数组不能直接传递给另一个进程,因为虚拟地址可能不同;也就是说,第一维数组指向其他数组的指针在任何其他进程上都没有意义。因此,您必须分别传递每个数组,并在接收方手动重新组装您的“二维数组”。
2)广播与散射。广播将完整的数组发送到通信器中的所有其他MPI等级。相反,散射将源数组分布到所有其他MPI等级上。也就是说,使用广播,每个等级都会接收源数组的副本,而使用散射,每个等级都会接收数组的不同部分。