首页 > 解决方案 > 如何使用 MPI_Scatterv 将块大小发送到特定进程?

问题描述

随着使用

MPI_Scatterv(sendbuf[], sendcounts[], displs[], sendtype, recvbuf[], recvcount, recvtype, root, comm)

两个数组用于处理要发送到特定进程的可变长度数据块大小:sendcounts 和 displs。第一个是要发送到每个进程的元素数,而 displs 是 sendbuf 的起始索引,从中计算 sendcounts - 但每个进程的接收缓冲区长度相同。在这种情况下,我如何告诉每个进程它应该读取其 recbuf[] 的多少元素来处理?即进程 0 将获得 1 个元素,进程 1 将获得 3 个元素,但它们都有 recbuf[] 长度为 4 个元素。

标签: cmpi

解决方案


我发现的一个简单解决方案就是为每个等级初始化 sendcounts[] 数组。当相同的数据生成的次数与所涉及的等级一样多时,这将浪费一些内存,但是这样所有的数据都将具有相同的数据,并且都将确切地知道要从其特定的 recbuf 中读取多少元素。以下是根据这种方法的实施示例。如果我以任何方式做错了,请看一下并纠正我 - 欢迎所有评论。

编辑2:

@GillesGouaillardet 基于您的第二个答案(关于 f())我再次修改了代码,现在每个等级都根据函数输出获取其 recbuf 长度 - 现在除了根等级之外不使用 recbuf 数组。

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define DISPLACEMENT_SIZE 4

int getsendcount(int);

int main(int argc, char **argv)
{
        int rank, size;

        MPI_Init(&argc,&argv);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Comm_size(MPI_COMM_WORLD, &size);

        int *rcvbuf = malloc(getsendcount(rank) * sizeof(int));

        // root node will initialize input array of data and displacements when only root needs them for Scatter
        if(!rank)
        {
                int *intab, *sendcounts, *displs;
                int displacement = 0;
                displs = malloc(size * sizeof(int));
                sendcounts = malloc(size * sizeof(int));
                int f = 0, mainindex = 0;
                intab = malloc(size * DISPLACEMENT_SIZE * sizeof(int));

                // every rank will get its own chunk of data, but all will get SAME copy
                for(int i=0; i < size; i++)
                {
                        *(sendcounts + i) = getsendcount(i);
                }

                // generating input data array
                for(int i=0; i < size; i++)
                {
                        for(int j=0; j < DISPLACEMENT_SIZE; j++)
                        {
                                *(intab+mainindex) = 1*f;
                                mainindex++;
                        }
                        f += 10;
                }

                // initializing displacements array, every DISPLACEMENT_SIZE fields for each rank
                for(int i=0; i < size; i++)
                {
                        *(displs + i) = displacement;
                        displacement += DISPLACEMENT_SIZE;
                }

                // debug block to see values
                for(int i=0; i < size; i++)
                {
                        printf("displs[%i] = %i, sendcounts[%i] = %i\n", i, *(displs+i), i, sendcounts[i]);
                }
                putchar('\n');

                for(int i=0; i < mainindex; i++)
                {
                        printf("%i ", *(intab + i));
                }
                putchar('\n');

                MPI_Scatterv(intab, sendcounts, displs, MPI_INT,rcvbuf, getsendcount(rank), MPI_INT, 0, MPI_COMM_WORLD);
        }
        else
        {
                MPI_Scatterv(NULL, NULL, NULL, NULL ,rcvbuf, getsendcount(rank), MPI_INT, 0, MPI_COMM_WORLD);
        }

        printf("this is proces %i, got: sendcounts %i\n", rank, getsendcount(rank));

        for(int i=0; i < getsendcount(rank); i++)
        {
                printf("Process %i my %i buffer value is %i\n ", rank, i, *(rcvbuf + i));
        }
        MPI_Finalize();

        return 0;

        }

int getsendcount(int i)
{
        return i - (i/DISPLACEMENT_SIZE * DISPLACEMENT_SIZE) + 1;
}

推荐阅读