C ++将整数数组分成块
C++ split integer array into chunks
我想我的问题有两部分:
(1) 这是将数组的不同块发送到不同处理器的正确方法吗?
假设我有 n
个处理器,其等级范围从 0
到 n-1
。
我有一个大小为 d
的数组。我想将此数组拆分为 k
个大小相等的块。假设 d
可以被 k
整除。
我想将这些块中的每一个发送到等级小于 k
的处理器。
如果我可以使用 MPI_Scatter 之类的东西会很容易,但是这个函数会发送到所有其他处理器,而我只想发送到一定数量的 proc。
所以我所做的是我有一个 k
迭代循环并执行 k
MPI_Isend
。
这样有效率吗?
(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);
}
您正在寻找的是 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
表现更好,因此这是最佳解决方案。
我想我的问题有两部分:
(1) 这是将数组的不同块发送到不同处理器的正确方法吗?
假设我有 n
个处理器,其等级范围从 0
到 n-1
。
我有一个大小为 d
的数组。我想将此数组拆分为 k
个大小相等的块。假设 d
可以被 k
整除。
我想将这些块中的每一个发送到等级小于 k
的处理器。
如果我可以使用 MPI_Scatter 之类的东西会很容易,但是这个函数会发送到所有其他处理器,而我只想发送到一定数量的 proc。
所以我所做的是我有一个 k
迭代循环并执行 k
MPI_Isend
。
这样有效率吗?
(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);
}
您正在寻找的是 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
表现更好,因此这是最佳解决方案。