【问题标题】:MPI joining vectorsMPI 连接向量
【发布时间】:2014-01-27 16:49:18
【问题描述】:

我正在尝试进行一些并行计算,然后将它们简化为一个向量。

我尝试将 for 循环分成应该与向量分开计算的部分。稍后我想将所有这些子向量加入一个主向量,方法是用从进程中获得的值替换其中的一部分。不用说,我不知道该怎么做,我的尝试都是徒劳的。

任何帮助将不胜感激。

MPI_Barrier(MPI_COMM_WORLD);
MPI_Bcast(A, n*n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast(b, n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast(x0, n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
printf("My id: %d, mySize: %d, myStart: %d, myEnd: %d", rank, size, mystart, myend);
while(delta > granica)
{
    ii++;
    delta = 0;
    //if(rank > 0)
    //{
        for(i = mystart; i < myend; i++)
        {
            xNowe[i] = b[i];
            for(j = 0; j < n; j++)
            {
                if(i != j)
                {
                    xNowe[i] -= A[i][j] * x0[j];
                }
            }
            xNowe[i] = xNowe[i] / A[i][i];
            printf("Result in iteration %d: %d", i, xNowe[i]);
        }
        MPI_Reduce(xNowe, xNowe,n,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);

【问题讨论】:

    标签: c parallel-processing mpi


    【解决方案1】:

    我将忽略您的计算,并假设他们都在做您希望他们做的任何事情,最后,您有一个名为 xNowe 的数组,其中包含您的排名结果(在某个子数组中)。

    你有两个选择。

    第一种方式使用MPI_REDUCE,就像您当前的做法一样。

    需要发生的是,您可能应该将所有与您的等级无关的值设置为 0,然后您可以做一个大的MPI_REDUCE(正如您已经在做的那样),每个进程都有贡献它的xNowe 数组看起来像这样(取决于输入/排名/等):

    rank:    0   1   2   3   4   5   6   7
    value:   0   0   1   2   0   0   0   0
    

    当您进行归约时(以MPI_SUM 作为操作),您将获得一个数组(在等级 0 上),其中每个值都填充有每个等级贡献的值。

    第二种方式使用MPI_GATHER有些人可能认为这是“更合适”的方式。

    对于此版本,您无需使用MPI_REDUCE 来获取结果,而是仅发送根据您的排名计算的数据。你不会有一个大数组。所以你的代码看起来像这样:

    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Bcast(A, n*n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    MPI_Bcast(b, n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    MPI_Bcast(x0, n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    MPI_Barrier(MPI_COMM_WORLD);
    printf("My id: %d, mySize: %d, myStart: %d, myEnd: %d", rank, size, mystart, myend);
    while(delta > granica)
    {
        ii++;
        delta = 0;
    
        for(i = mystart; i < myend; i++)
        {
            xNowe[i-mystart] = b[i];
            for(j = 0; j < n; j++)
            {
                if(i != j)
                {
                    xNowe[i] -= A[i][j] * x0[j];
                }
            }
            xNowe[i-mystart] = xNowe[i-mystart] / A[i][i];
            printf("Result in iteration %d: %d", i, xNowe[i-mystart]);
        }
    }
    MPI_Gather(xNowe, myend-mystart, MPI_DOUBLE, result, n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    

    您显然需要在等级 0 上创建一个名为 result 的新数组来保存结果值。

    更新:

    正如 Hristo 在下面的 cmets 中指出的那样,如果 myend - mystart 在所有等级上都不相同,MPI_GATHER 可能无法在这里工作。如果是这种情况,您需要使用MPI_GATHERV,它允许您为每个等级指定不同的大小。

    【讨论】:

    • 因此,如果我想以最简单的方式进行操作,我基本上需要将除我想要的值之外的值设置为 0 并像我所做的那样对其求和。好吧,我还有一个问题,我的 MPI_Reduce 抛出了这样一个错误(知道出了什么问题吗?): PMPI_Reduce 中的致命错误:缓冲区指针无效,错误堆栈:MPI_Reduce(sbuf=0x045EC150, rbuf=0x045EC150, count=1000, MPI_DOUBLE, MPI_SUM, ro ot=0, MPI_COMM_WORLD) failed 缓冲区参数 sendbuf 和 recvbuf 不能有别名
    • 您正在为发送和接收缓冲区使用相同的缓冲区(这就是最后一位“sendbuf 和 recvbuf 不得别名”的意思)。如果你想这样做,你需要为发送缓冲区使用MPI_IN_PLACE 选项。
    • 很抱歉打扰您,但在尝试在 2 个进程上运行它时又遇到了一个问题:[ranks] 消息 [0] 终止 [1] 致命错误 PMPI_Reduce 中的致命错误:缓冲区指针无效,错误堆栈:MPI_Reduce(sbuf=MPI_IN_PLACE, rbuf=0x0496E118, count=1000, MPI_DOUBLE, MPI_SUM, root=0, MPI_COMM_WORLD) 失败 sendbuf 不能是 MPI_IN_PLACE
    • 使用MPI_Gather 不是“更合适” - 它是正确 完成任务的方式:) 此外,由于OP 没有显示myend-mystart在所有进程中都是平等的,MPI_Gatherv 可能更合适。
    • 使用复制数据通常更容易,因为它模仿了共享内存编程。但随后不可避免地会出现必须收集结果的时刻。
    猜你喜欢
    • 2018-07-21
    • 2016-07-18
    • 1970-01-01
    • 2012-10-23
    • 2023-02-07
    • 2023-03-09
    • 2016-01-23
    • 2013-02-16
    • 2013-02-19
    相关资源
    最近更新 更多