我想我的问题有两部分:
(1)这是将数组的不同块发送到不同处理器的正确方法吗?
我们假设我有n
个处理器,其等级范围从0
到n-1
。
我有一个大小为d
的数组。我想将此数组拆分为k
同样大小的块。假设d
可被k
整除。
我想将这些块中的每一个发送到级别小于k
的处理器。
如果我可以使用像MPI_Scatter这样的东西会很容易,但是这个函数会发送给每个其他处理器,我只想发送到一定数量的proc。
所以我所做的就是我有一个k
次迭代的循环并执行k
MPI_Isend
&#39}。
这有效吗?
(2)如果是,如何将数组拆分成块?
总是很简单的方法int size = d/k;
int buffs[k][size];
for (int rank = 0; rank < k; ++rank)
{
for (int i = 0; i < size ++i)
buffs[rank][i] = input[rank*size + i];
MPI_Isend(&buffs[rank], size, MPI_INT, rank, 1, comm, &request);
}
答案 0 :(得分:1)
您正在寻找的是MPI_Scatterv
,它允许您明确指定每个块的长度及其相对于缓冲区开头的位置。如果您不想将数据发送到某些等级,只需将其长度设置为0:
int blen[n];
MPI_Aint displ[n];
for (int rank = 0; rank < n; rank++)
{
blen[rank] = (rank < k) ? size : 0;
displ[rank] = rank * size;
}
int myrank;
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
MPI_Scatterv(input, blen, displ, MPI_INT,
mybuf, myrank < k ? size : 0, MPI_INT,
0, MPI_COMM_WORLD);
请注意,对于rank >= k
,置换将超过缓冲区的末尾。这是正确的,因为rank >= k
的块长度设置为零,并且不会访问任何数据。
至于您的原始方法,它不可移植,可能并不总是有效。原因是您正在覆盖相同的request
句柄,您永远不会等待发送完成。正确的实施是:
MPI_Request request[k];
for (int rank = 0; rank < k; ++rank)
{
MPI_Isend(&input[rank*size], size, MPI_INT, rank, 1, comm, &request[rank]);
}
MPI_Waitall(k, request, MPI_STATUSES_IGNORE);
最佳实现方式是在子通信器中使用MPI_Scatter
:
MPI_Comm subcomm;
MPI_Comm_split(MPI_COMM_WORLD, myrank < k ? 0 : MPI_UNDEFINED, myrank,
&subcomm);
// Now there are k ranks in subcomm
// Perform the scatter in the subcommunicator
if (subcomm != MPI_COMM_NULL)
MPI_Scatter(input, size, MPI_INT, mybuf, size, MPI_INT, 0, subcomm);
MPI_Comm_split
来电分割MPI_COMM_WORLD
,并创建一个来自所有原始排名低于k
的新通讯器。它使用原始等级作为对新通信器中的等级进行排序的关键,因此MPI_COMM_WORLD
中的等级0变为subcomm
中的等级0。由于MPI_Scatter
的效果通常优于MPI_Scatterv
,因此这是最佳解决方案。