如何在MPI中的进程之间大致均匀地共享工作,尽管数组大小不能被进程数完全整除?

如何在MPI中的进程之间大致均匀地共享工作,尽管数组大小不能被进程数完全整除?,mpi,Mpi,大家好,我有一个长度为N的数组,我想在“大小”处理器之间尽可能最好地划分它。N/size有一个余数,例如1000个数组元素除以7个进程,或14个进程除以3个进程 我知道MPI中至少有几种工作共享方式,例如: for(i=rank;i我认为最好的解决方案是为自己编写一个小函数,以便在进程之间足够均匀地分割工作。这里有一些伪代码,我相信你可以比我更好地编写C(你的问题中是C吗?) function split_evenly_enough(num_steps, num_processes) r

大家好,我有一个长度为N的数组,我想在“大小”处理器之间尽可能最好地划分它。N/size有一个余数,例如1000个数组元素除以7个进程,或14个进程除以3个进程

我知道MPI中至少有几种工作共享方式,例如:


for(i=rank;i我认为最好的解决方案是为自己编写一个小函数,以便在进程之间足够均匀地分割工作。这里有一些伪代码,我相信你可以比我更好地编写C(你的问题中是C吗?)

function split_evenly_enough(num_steps, num_processes)
    return = repmat(0, num_processes)  ! pseudo-Matlab for an array of num_processes 0s
    steps_per_process = ceiling(num_steps/num_processes)
    return = steps_per_process - 1 ! set all elements of the return vector to this number
    return(1:mod(num_steps, num_processes)) = steps_per_process  ! some processes have 1 more step
end
以您的“1000个步骤和7个过程”为例

  • 简单除法不起作用,因为整数除法(在C中)给了你底数,剩下一些余数:即1000/7是142,将有6个doodas挂在外面

  • 天花板分割有一个相反的问题:ceil(1000/7)是143,但最后一个处理器溢出了阵列,或者比其他处理器的任务要少

您要求的是一个在处理器上平均分配剩余部分的方案。一些进程应该有142个,其他的143个。必须有一个更正式的方法,但考虑到这个问题在过去六个月内得到的关注,可能没有

这是我的方法。每个进程都需要做这个算法,只需要为自己挑选出它需要的答案

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char ** argv)
{
#define NR_ITEMS 1000
    int i, rank, nprocs;;
    int *bins;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
    bins = calloc(nprocs, sizeof(int));

    int nr_alloced = 0;
    for (i=0; i<nprocs; i++) {
        remainder = NR_ITEMS - nr_alloced;
        buckets = (nprocs - i);
        /* if you want the "big" buckets up front, do ceiling division */
        bins[i] = remainder / buckets;
        nr_alloced += bins[i];
    }

    if (rank == 0)
        for (i=0; i<nprocs; i++) printf("%d ", bins[i]);

    MPI_Finalize();
    return 0;
}
#包括
#包括
#包括
int main(int argc,字符**argv)
{
#定义NR_项目1000
国际一级,排名,非专利法公约;;
int*垃圾箱;
MPI_Init(&argc,&argv);
MPI通信等级(MPI通信世界和等级);
MPI通信大小(MPI通信世界和NPROC);
bins=calloc(nprocs,sizeof(int));
分配的整数=0;

对于(i=0;i如果我有
N
任务(例如数组元素)和
size
工作者(例如MPI等级),我将如下所示:

int count=N/大小;
整数余数=N%大小;
int启动、停止;
if(秩<余数){
//第一个“剩余”列组每个列组获得“计数+1”个任务
开始=排名*(计数+1);
停止=开始+计数;
}否则{
//剩余的“大小-剩余”列组每个任务获得“计数”
开始=排名*计数+余数;
停止=启动+(计数-1);
}
对于(inti=start;i这个怎么样

int* distribute(int total, int processes) {
    int* distribution = new int[processes];
    int last = processes - 1;        

    int remaining = total;
    int process = 0;

    while (remaining != 0) {
        ++distribution[process];
        --remaining;

        if (process != last) {
            ++process;
        }
        else {
            process = 0;
        }
    }

    return distribution;
}
其思想是将一个元素分配给第一个进程,然后将一个元素分配给第二个进程,然后将一个元素分配给第三个进程,依此类推,只要到达最后一个进程,就跳回第一个进程


即使进程的数量大于元素的数量,这种方法也能工作。它只使用非常简单的操作,因此应该非常快。

我也有类似的问题,下面是我使用Python和mpi4py API的非最佳解决方案。最佳解决方案将考虑处理器的布局,这里是额外的工作分配给下级。不均匀的工作量只因一项任务不同而不同,所以一般来说这不是什么大问题

从MPI4p导入MPI
导入系统
def get_start_end(通信,N):
"""
分布N个连续的事物(矩阵的行、1D数组的块)
在给定的通讯器上尽可能均匀。
初始级别上的工作量不均匀(最多相差1)。
参数
----------
通讯器:MPI通讯器
N:int
要分发的内容的总数。
退换商品
----------
rstart:第一个本地行的索引
趋势:1+最后一行的索引
笔记
----------
索引是以零为基础的。
"""
P=通信大小
秩=通信秩
rstart=0
rend=N
如果P>=N:
如果秩=余数:
rstart+=余数
rend+=余数
其他:
rstart+=秩
rend+=排名+1
返回rstart,rend
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
comm=MPI.comm_WORLD
n=int(sys.argv[1])
打印(comm.rank,get\u start\u end(comm,n))

我知道这已经过去很久了,但一个简单的方法是为每个进程指定(项目数)/(进程数)+(如果进程数
# Number of items
NI=128
# Number of processes
NP=20

# Items per process
[NI/NP + (1 if P < NI%NP else 0)for P in range(0,NP)]
#项目数量
NI=128
#进程数
NP=20
#每个流程的项目
[NI/NP+(如果P
这是一个封闭形式的解决方案

设N=数组长度,p=处理器数量

从j=0到p-1

处理器上阵列的起点j=地板(N*j/p)


处理器上阵列的长度j=地板(N*(j+1)/p)–地板(N*j/p)

改进@Alexander的答案:利用
min
压缩逻辑

int count = N / size;
int remainder = N % size;
int start = rank * count + min(rank, remainder);
int stop = (rank + 1) * count + min(rank + 1, remainder);

for (int i = start; i < stop; ++i) { a[i] = DO_SOME_WORK(); }
int count=N/大小;
整数余数=N%大小;
整数开始=秩*计数+最小值(秩,余数);
整数停止=(秩+1)*计数+min(秩+1,余数);
对于(inti=start;i
内存和时间的复杂性是O(NPROC)。请小心,因为这可能会影响大量进程的内存和性能。