看到这个题目,俗了,大家都在计算圆周率。不过咱们的目的是看一下并行计算的基本流程。
书上计算PI用的是精确的数值计算方法,我这里再给出一种概率计算方法。
OpenMP和MPI将同时亮相。
计算PI的方法
1.tan(PI/4)=1 => PI=4arctan1。知道arctan1转化为定积分的形式是什么吧。
05 | double local,pi=0.0,w; |
11 | pi=pi+4.0/(1.0+local*local); |
14 | printf("PI is %.20f/n",pi*w); |
15 | printf("Time: %.2f seconds/n",(float)(t2-t1)/CLOCKS_PER_SEC); |
orisun@orisun-desktop:~/Program$ ./PI1
PI is 3.14159265358976336202
Time: 0.02 seconds
2.以坐标原点为形心,作半径为1的圆和边长为2的正方形。正方形与圆的面积之比即为PI
09 | srand((unsigned)time(NULL)); |
13 | x=(double)rand()/RAND_MAX; |
14 | y=(double)rand()/RAND_MAX; |
19 | printf("PI is %.20f/n",4*(double)sum/N); |
20 | printf("Time: %.2f/n",(float)(t2-t1)/CLOCKS_PER_SEC); |
orisun@orisun-desktop:~$ ./PI0
PI is 3.14301599999999980994
Time: 0.16
对比可以看到方法1在计算精度和速度上都具有绝对的优势。在下面的openMP和MPI计算中我们都采用方法1。
OpenMP
OpenMP[OMP]是一个编译器指令和库函数的集合(已包含在gcc中),它用于为共享存储器计算机创建并行程序。OMP组合了C、C++和Fortran。
06 | double local,pi=0.0,w; |
10 | #pragma omp parallel for private(local) reduction(+:pi) |
13 | pi=pi+4.0/(1.0+local*local); |
16 | printf("PI is %.20f/n",pi*w); |
17 | printf("Time: %.2f seconds/n",(float)(t2-t1)/CLOCKS_PER_SEC); |
orisun@orisun-desktop:~/Program$ ./PI2
PI is 3.14159265358976336202
Time: 0.02 seconds
跟串行计算结果是一模一样。
#pragma omp parallel表示下面的一行代码或代码块要分配到多个执行单元中并行计算。
#pragma omp parallel for用在一个for循环的前面
private(local)默认情况下定义在并行代码之外的变量为各并行的执行单元所共享,使用private限制,表示每个执行单元创建该变量的一个副本
reduction(+:pi)表示并行代码执行完毕后对各个执行单元中的pi进行相加操作
MPICH2
ubuntu下mpich2的安装配置见这位老兄的博客http://hi.baidu.com/mousetwo/blog/item/ddba71a9b0adf4f11f17a2fc.html
MPI(Message Parsing Interface)消息传递接口是用于分布式存储器并行计算机的标准编程环境。MPI的核心构造是消息传递:一个进程将信息打包成消息,并将该消息发送给其他进程。MPI最常用的两个实现是LAM/MPI[LAM]和MPICH[MPI]。
在MPI中执行单元(UE)指的就是进程。
05 | int main(int argc,char *argv[]){ |
06 | int my_rank,num_procs; |
08 | double sum,width,local,mypi,pi; |
09 | double start=0.0,stop=0.0; |
11 | char processor_name[MPI_MAX_PROCESSOR_NAME]; |
13 | MPI_Init(&argc,&argv); |
14 | MPI_Comm_size(MPI_COMM_WORLD,&num_procs); |
15 | MPI_Comm_rank(MPI_COMM_WORLD,&my_rank); |
16 | MPI_Get_processor_name(processor_name,&proc_len); |
18 | printf("Processor %d of %d on %s/n",my_rank,num_procs,processor_name); |
20 | printf("please give n="); |
24 | MPI_Bcast(&n,1,MPI_INT,0,MPI_COMM_WORLD); |
27 | for(i=my_rank;i<n;i+=num_procs){ |
28 | local=width*((double)i+0.5); |
29 | sum+=4.0/(1.0+local*local); |
32 | MPI_Reduce(&mypi,&pi,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD); |
34 | printf("PI is %.20f/n",pi); |
36 | printf("Time: %f/n",stop-start); |
orisun@orisun-desktop:~/Program$ mpdboot
orisun@orisun-desktop:~/Program$ mpicc -o PI3 PI3.c
orisun@orisun-desktop:~/Program$ mpirun -np 4 ./PI3
Processor 0 of 4 on orisun-desktop
please give n=Processor 2 of 4 on orisun-desktop
Processor 1 of 4 on orisun-desktop
Processor 3 of 4 on orisun-desktop
1000000
PI is 3.14159465358887635134
Time: 0.012510
orisun@orisun-desktop:~/Program$ mpdcleanup
时间是0.01251秒,比0.02秒明显减少。
注意输出中有这么一行:please give n=Processor 2 of 4 on orisun-desktop
这说明是我们不能保证代码中的18行和20行的执行顺序。
Reference: http://www.cnblogs.com/zhangchaoyang/articles/1871168.html