我需要将一个整数数组(基本上是一个二维数组)从根目录传递给所有处理器。我在 C 程序中使用 MPI。如何声明二维数组的 MPI 数据类型。以及如何发送消息(我应该使用广播还是分散)
4 回答
您需要使用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
但是,您还没有完成。接收进程需要知道您发送的数组的大小:如果该知识在编译时不可用,您必须先发送带有该数据的单独消息(简单的整数数组)。如果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);
注意:您可能会使用Indexed类型而不是 HIndexed。不同之处在于,在 Indexed 中,displacements
数组以元素数量给出,而在 HIndexed 中,它是字节数(H 代表 Heterogenous)。如果您要使用索引,则给出的值displacements
必须除以sizeof(int)
. 但是,我不确定在堆上的任意位置定义的整数数组是否保证“对齐”到 C++ 中的整数限制,并且在任何情况下,HIndexed 版本的代码(略微)更少并产生相同的结果。
如果您要发送一个连续的数据块(我认为 C 数组是连续的,但我是 Fortran 程序员并且不太确定),您不需要声明新的 MPI 数据类型,尽管有一些原因您可能会想要。分散是为了在多个进程中分布一个数组。您可以使用 scatter 将数组的每一行发送到不同的进程。因此,对于您的连续整数数组示例,您最简单的选择是广播,如下所示(记住我糟糕的 C 技能):
MPI_Bcast(&buf, numRows*numCols, MPI_INT, root, MPI_COMM_WORLD)
在哪里
&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 等级。Scatter,OTOH,将源数组分布在所有其他 MPI 等级上。即广播每个等级接收源数组的副本,散布每个等级接收数组的不同部分。