【问题标题】:Why is the result when executing this C MPI application for Pi approximation always the same?为什么执行这个 C MPI 应用程序进行 Pi 近似时的结果总是相同的?
【发布时间】:2017-10-27 08:54:09
【问题描述】:

这个用于 Pi 近似的 C MPI 应用程序总是打印出每个问题大小的相同结果,即随机生成的点数 (npts)。

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

int main(int argc, char *argv[]) {

  int myid,nprocs;

  double PI25DT = 3.141592653589793238462643;

  long long npts = 1e10;

  long i,mynpts;

  long double f,sum,mysum;
  long double xmin,xmax,x;

  MPI_Init(&argc,&argv);
  MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
  MPI_Comm_rank(MPI_COMM_WORLD,&myid);

  if (myid == 0) {
    mynpts = npts - (nprocs-1)*(npts/nprocs);
  } else {
    mynpts = npts/nprocs;
  }

  mysum = 0.0;
  xmin = 0.0;
  xmax = 1.0;

  srand(myid);  

  for (i=0; i<mynpts; i++) {
    x = (long double) rand()/RAND_MAX*(xmax-xmin) + xmin;
    mysum += 4.0/(1.0 + x*x);
  }

  MPI_Reduce(&mysum,&sum,1,MPI_LONG_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);

  if (myid == 0) {
    f = sum/npts;
    printf("PI calculated with %lld points = %.16f \n",npts,f);
    printf("Error is: %.16f \n",fabs(f-PI25DT));
  }

  MPI_Finalize();
}  

这是输出。我认为每次运行应用程序的结果应该会有所不同。我在一个有 128 个节点的集群上执行它。

$ mpicc pi.c -o /mnt/cluster_128/pi
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi  /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi  /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi  /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi  /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 

【问题讨论】:

    标签: c parallel-processing mpi pi srand


    【解决方案1】:

    您在此处播种 PRNG:

    srand(myid);
    

    myid 是通过调用MPI_Comm_rank() 设置的值,并且您只对myid == 0 的结果感兴趣,因此这始终是相同的值。播种相同的值会产生相同的“随机”数字序列。

    改用播种的常用习语:

    #include <time.h>
    #include <stdlib.h>
    
    [...]
    
    srand(time(0));
    

    【讨论】:

    • 这是MPI_Comm_rank的输出
    • @WeatherVane 播种有用吗?那我就删掉这个答案...
    • 否,因为代码只在if (myid == 0) 时打印结果
    【解决方案2】:

    您的代码仅在 if (myid == 0) 显示您的 RNG 种子无用时打印任何结果。

    我建议

    srand((unsigned)time(NULL));
    

    【讨论】:

      【解决方案3】:

      现有的答案已经指向正确的方向,但我认为他们的解释并不完全正确。

      如前所述,问题在于 RNG 种子。您使用myid 作为srand 的种子,它始终是0N-1 之间的数字(N 是等级数,即传递给mpiexec -np N executable 命令的数字)。这是确定性的:它不会因不同的执行而改变。

      因此,所有 N 个进程将创建相同的种子集,并且对于相同数量的进程,生成的随机数将相同:

      • 对于单个进程 (N=1):种子值始终为 0
      • 对于五个进程 (N=5):每个进程中的种子值始终为 0、1、2、3 和 4。等等。

      MPI_Reduce 集合收集来自每个进程的所有部分结果(由于随机数相同,它们产生相同的值)并在根进程 (myid=0) 中打印总和。带有myid 的进程是否打印结果这一事实并不重要,因为还有其他 N-1 个具有不同 myid 值的进程会影响正在打印的最终结果。

      2 个进程的小例子,myid:

      • Rank 0srand(0),计算部分和 (mysum),将其他进程的部分和累加到 sum 变量中(您指定 0 作为根进程在 MPI_Reduce 第 7 个参数中。打印结果(myid==0true)。

      • 排名 1srand(1),计算部分和 (mysum) 将其发送到 MPI_Reduce 根进程 (0)。不打印结果(myid==0false)。

      您需要了解 MPI 最重要的一点是,您通常执行具有多个进程的单个程序,并且这些进程中的每一个都会获得不同的环境MPI_Comm_rank 的输出参数)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-22
        • 2014-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-21
        相关资源
        最近更新 更多