一种方法是使用MPI_Scatter 并向数组添加填充,以便它的大小在进程之间均匀分割。但是,每当一个进程必须操作该数组时,它都需要忽略填充部分。
另一种方法是使用MPI_ScatterV,并在进程之间“手动”划分块。
这种方法的一个例子:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc,char *argv[]){
MPI_Init(NULL,NULL); // Initialize the MPI environment
int world_rank;
int world_size;
MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
MPI_Comm_size(MPI_COMM_WORLD,&world_size);
int size = 50;
int *numbers= NULL;
if(world_rank == 0){
numbers = malloc(sizeof(int) * size);
for(int i = 0; i < size; i++)
numbers[i] = (2*i + 1);
}
// The Important Part
int sendcounts [world_size];
int displs [world_size];
int res = size % world_size;
int size_per_process = size / world_size;
int increment = 0;
for(int processID = 0; processID < world_size; processID++){
displs[processID] = increment;
sendcounts[processID] = (processID + 1 <= res) ? size_per_process + 1 : size_per_process;
increment += sendcounts[processID];
}
int process_size = sendcounts[world_rank];
int local_numbers[process_size];
MPI_Scatterv(numbers, sendcounts, displs, MPI_INT, local_numbers, process_size, MPI_INT, 0, MPI_COMM_WORLD);
if(world_rank == world_size - 1){
for(int i = 0; i < size_per_process; i++)
printf("%d ", local_numbers[i]);
printf("\n");
}
MPI_Finalize();
return 0;
}
这有点令人费解,但好消息是这种类型的分布总是相同的。
代码说明:
首先我们要了解MPI_Scatterv的参数:
MPI_Scatterv
将缓冲区分散到通信器中的所有进程中
int MPI_Scatterv(const void *sendbuf, const int *sendcounts, const int *displs, MPI_Datatype sendtype, void *recvbuf, int recvcount,
MPI_Datatype recvtype, int root, MPI_Comm comm)
输入参数
sendbuf 发送缓冲区的地址(选择,仅在根处有效)
sendcounts 整数数组(长度为组大小),指定要发送到的元素数量每个处理器
displs 整数数组(长度为组大小)。条目 i 指定位移(相对于从其获取传出数据以处理 i
sendtype 发送缓冲区元素(句柄)的数据类型
recvcount接收缓冲区中的元素数(整数)
recvtype 接收缓冲区元素的数据类型(句柄)
root 发送进程的等级(整数)
comm 通讯器(句柄)
首先,我们创建包含每个进程将发送的元素数量的数组:
int sendcounts [world_size];
然后我们用位移创建数组:
int displs [world_size];
然后我们计算额外的迭代次数:
int res = size % world_size;
然后我们计算每个过程保证有的迭代次数:
int size_per_process = size / world_size;
最后,我们计算每个进程的大小和位移:
int increment = 0;
for(int processID = 0; processID < world_size; processID++){
displs[processID] = increment;
sendcounts[processID] = (processID + 1 <= res) ? size_per_process + 1 : size_per_process;
increment += sendcounts[processID];
}
行:
sendcounts[processID] = (processID + 1 <= res) ? size_per_process + 1 : size_per_process;
表示我们将从左到右分配额外的迭代(即从进程排名 0 到进程总数 - 1)。