如何使MPI_Send让处理器按顺序而不是随机发送

how to make MPI_Send have processors send in order instead of randomly?

本文关键字:随机 顺序 MPI 何使 Send 处理器      更新时间:2023-10-16

我正在尝试运行下面使用并行编程的程序。如果我们使用 4 个处理器,我希望它们包含总和 1+2=3、3+4=7、11 和 15。所以我希望求和向量按这个顺序包含 3、7、11 和 15。HOwever,由于MPI_Send处理器以随机顺序发送,所以我不会对向量求和以包含 7、15、3、11。如何修改下面的代码以确保这一点?

#include<iostream>
#include<mpi.h>

using namespace std;
int main(int argc, char *argv[]){
    int mynode, totalnodes;
    int sum,startval,endval,accum;
    MPI_Status status;
    int master=3; 
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD, &totalnodes); // get totalnodes
    MPI_Comm_rank(MPI_COMM_WORLD, &mynode); // get mynode
    sum = 0; // zero sum for accumulation
    vector <int> sumvector;
    startval = 8*mynode/totalnodes+1;
    endval = 8*(mynode+1)/totalnodes;
    for(int i=startval;i<=endval;i=i+1)
        sum=sum+i;
        sumvector.push_back(sum);
    if(mynode!=master)
    {
        MPI_Send(&sum,1,MPI_INT,master,1,MPI_COMM_WORLD); //#9, p.92
    }
    else
    {
        for(int j=0;j<totalnodes;j=j+1){
            if (j!=master)
            {
                MPI_Recv(&accum,1,MPI_INT,j,1,MPI_COMM_WORLD, &status);
                printf("processor %d  received from %dn",mynode, j);
                sum = sum + accum;
            }
        }
    }

我使用多线程而不是 MPI 更好吗?

我不确定你想做什么,但你当前的代码是等效的(没有打印从哪个等级收到的数字)到下面的代码:

for(int i=startval;i<=endval;i=i+1)
    sum=sum+i;
sumvector.push_back(sum);
MPI_Reduce(mynode == master ? MPI_IN_PLACE : &sum, &sum, 1, MPI_INT,
           master, MPI_COMM_WORLD);

您正在寻找的是以下之一(结果仅由主等级收集):

for(int i=startval;i<=endval;i=i+1)
    sum=sum+i;
sumvector.resize(totalnodes);
MPI_Gather(&sum, 1, MPI_INT, &sumvector[0], 1, MPI_INT,
           master, MPI_COMM_WORLD);

或者这个(结果收集到所有等级):

for(int i=startval;i<=endval;i=i+1)
    sum=sum+i;
sumvector.resize(totalnodes);
MPI_Allgather(&sum, 1, MPI_INT, &sumvector[0], 1, MPI_INT, MPI_COMM_WORLD);

此外,以下陈述是完全错误的:

HOwever,由于MPI_Send处理器以随机顺序发送,所以我不会对向量求和以包含 7、15、3、11。

MPI点对点通信需要两件事才能成功:必须有一个执行MPI_Send发送方和一个执行匹配MPI_Recv接收方。消息接收顺序可以通过简单地在循环中调用MPI_Recv来强制执行,并增加源秩,就像您显示的代码中一样。

有许多

方法可以更简单地执行此操作。首先,您可以将值"收集"到主进程上的向量中:

std::vector <int> sumvector, recvcounts, displs;
startval = 8*mynode/totalnodes+1;
endval = 8*(mynode+1)/totalnodes;
for (int i=0; i<totalnodes; i++)
{
    sumvector.push_back(0);
    recvcounts.push_back(1);
    displs.push_back(i);
}
int myval = startval + endval;
MPI_Gatherv(&myval,
            1,
            MPI_INTEGER,
            &sumvector[0],
            &recvcounts[0],
            &displs[0],
            MPI_INTEGER,
            master,
            MPI_COMM_WORLD);

这导致求和向量包含:

node 0: (0, 0, 0, 0)
node 1: (0, 0, 0, 0)
node 2: (0, 0, 0, 0)
node 3: (3, 7, 11, 15)

您也可以考虑MPI_Allreduce。该过程将如下所示:

将所有向量元素初始化为 0,

for (int i=0; i<totalnodes; i++)
{
    sumvector.push_back(0);
}

并将Mynode的条目修改为您想要的值,

sumvector[mynode] = startval + endval;

在MPI_Allreduce之前,求和向量包含:

node 0: (3, 0, 0, 0)
node 1: (0, 7, 0, 0)
node 2: (0, 0, 11, 0)
node 3: (0, 0, 0, 15)

现在,当您对每个节点上的所有数组求和时,

MPI_Allreduce(MPI_IN_PLACE, 
              &sumvector[0], 
              totalnodes, 
              MPI_INTEGER, 
              MPI_SUM, 
              MPI_COMM_WORLD);

它导致求和向量包含:

node 0: (3, 7, 11, 15)
node 1: (3, 7, 11, 15)
node 2: (3, 7, 11, 15)
node 3: (3, 7, 11, 15)

在每个节点上。