【问题标题】:Parallelize double sum in C with MPI使用 MPI 并行化 C 中的双和
【发布时间】:2017-05-11 06:41:10
【问题描述】:

我在 C 中有这个函数 Sum(),我想使用 MPI 进行并行化:

double Sum(double* x, double* y, int n)
{
    double V = 0.0;
    int i, j;

    for (i = 0; i < n; i++)
    {
        for (j = 0; j < n; j++)
        {
            if (i != j)
                V += F(x[i], y[j]);
        }
    }

    return V;
}

其中F(x[i],y[j]) 只是一个函数,用于计算两个元素之间的差异或类似的二元运算。

现在我认为我可以将各个处理器上的总和分开 p 使用 MPI_Scatter() 以生成本地 vecotr,然后使用 MPI_Reduce() 将本地总和合并在一起,不幸的是,我似乎无法做到它。这是我的解决方案,但它似乎不起作用:

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

double Parallel_Sum(double (*)(double, double), double*, double*, int, int);
double F(double, double);

int main(int argc, char** argv)
{
    int my_rank, p;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    MPI_Comm_size(MPI_COMM_WORLD, &p);
    int n = 10;
    double *y = calloc(n, sizeof(double)), *x = calloc(n, sizeof(double));
    /*just for trial*/
    y[5] = 1;
    x[5] = 1;
    double* local_x = calloc(n / p, sizeof(double));
    MPI_Scatter(x, n / p, MPI_DOUBLE, local_x, n / p, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    double local_S, S = 0.0;
    local_S = Parallel_Sum(F, local_x, y, n, p);

    MPI_Reduce(&local_S, &S, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    if (my_rank == 0)
    {
        printf("%lf\n", S);
    }

    MPI_Finalize();
    return 0;
}

double F(double a, double b)
{
    return a - b;
}
double Parallel_Sum(double (*OP)(double, double), double* local_x, double* y, int n, int p)
{
    double local_V = 0.0;
    int i, j;

    for (i = 0; i < n / p; i++)
    {
        for (j = 0; j < n; j++)
        {
            if (i != j)
                local_V += OP(local_x[i], y[j]);
        }
    }

    return local_V;
}

在这个例子中,总和应该是 0,因为除了 y[5] = 1; x[5] = 1; 之外的向量都是零,不幸的是对于 p &gt; 1 它永远不会是零。我做错了什么?

【问题讨论】:

  • 好像不行?请具体并提供最小且可验证的代码。
  • 是的,抱歉,我编辑了问题
  • if (i != j) 在最内层循环中应该是if ((n/p) * my_rank + i != j),否则您将本地索引与全局索引进行比较。

标签: c mpi


【解决方案1】:
double Parallel_Sum(double (*OP)(double,double),double* local_x,double* y,int n,int p, int rank){

    double local_V = 0.0;
    int i,j;

    for(i = rank*n/p;i<(rank+1)*n/p;i++){ // <-- changed
        for(j = 0;j<n;j++){    

            if(i != j)
                local_V += OP(local_x[i-rank*n/p],y[j]); // <-- changed                 
        }
    }

    return local_V;    
}

【讨论】:

  • 谢谢!您能否详细说明一下为什么会这样?
  • 关于 for 循环,假设您使用单处理器运行。然后0&lt;i&lt;10。但是当np=2,对于每个处理器,你有0=&lt;i&lt;5,这仅适用于第一个处理器。对于第二个处理器,它应该是5=&lt;i&lt;10
【解决方案2】:

虽然local_x 中的索引很好,但对i != j 的检查却不行。您必须考虑 i 涵盖全局数组的不同部分,例如像这样:

double Parallel_Sum(double (*OP)(double, double), double* local_x, double* y, int n, int p, int rank)
{
    double local_V = 0.0;
    int i, j;

    for (i = 0; i < n / p; i++)
    {
        for (j = 0; j < n; j++)
        {
            if ((i + rank * (n / p)) != j)
                local_V += OP(local_x[i], y[j]);
        }
    }

    return local_V;
}

【讨论】:

  • 您的答案不适用于处理器数量大于两个的情况。
  • 我修正了偏移量计算。
  • 你能具体点吗?显然,我确实假设 n 可以被 p 整除,就像所有其余代码一样。
  • 对不起,我傻了。由于我的回答(巧合)甚至适用于奇数个处理器,这让我认为你的答案是错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
  • 2016-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
相关资源
最近更新 更多