【IT168 技术】
注:本文为IT168&NVIDIA联合举办的“如何并行化我的应用”方案征集活动参赛作品。本次方案征集活动详情见:http://cuda.itpub.net/thread-1299715-1-1.html。近期活动的大部分方案,将会逐步与大家分享,不可错过哦!
CUDA ZONE专区:http://cuda.it168.com/
CUDA技术论坛:http://cuda.itpub.net
我第一次听说“并行计算”这个词,还是在学校读研时学校举行的一次编程竞赛中:其中有一道题目要求用“利用并行计算的思想编程实现求π的近似值”。因为以前从没有接触过“并行计算”,当我刚拿到题目的时候,在先简单了解了一下“并行计算”的思想之后,就开始在网上找大量的关于并行计算的应用资料,然后就错误的认为只要设计一个多线程的程序就可以了,对于CPU来说还不都是在串行计算吗?是不是又是一个旧酒装新瓶的事情,这个性能又能优化到哪里去,顶多调一调线程间的竞争模式不就可以了?
但是在经过几天的学习后,我发现自己的方向和思路完全错了,所谓的“并行计算”不能简单的等同“多线程”,它真正是在并行执行多个任务,早就应用于图像、视频等需要高新能计算的领域,能够大大提高计算效率。调整了思路以后,我决定重新开始,仔细学习了《并行程序设计入门》文章中介绍的相关内容,并使用了其介绍的方法,分步骤完成这个题目。
1、首先进行数学分析
根据下面的积分公式:
令函数f(x)=4/(1+x2),则有:
而f(x)的图象为:
计算f(x)图象下面从0到1之间的面积即为π的值。而该面积可以用图示的5个小矩形面积的和来近似,矩形的高度取函数在矩形中间点的取值,当用更多的矩形来划分时,该近似值就越接近于真实的π值,设将0到1的区间划分为N个矩形,则近似公式为:
将N个矩形面积分别交由多个进程并行计算,再将并行计算得到的各矩形面积累加,求得π的近似值。
2、编程实现
由上,可得求π值的程序如下:
#include <stdio.h>
#include <math.h>
double f(double);
double f(double x)
/* 定义函数f(x) */
{
return (4.0 / (1.0 + x*x));
}
int main(int argc,char *argv[])
{
int done = 0, n, myid, numprocs, i;
double PI25DT = 3.141592653589793238462643;
/* 先给出已知的较为准确的π值*/
double mypi, pi, h, sum, x;
double startwtime = 0.0, endwtime;
int namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
MPI_Get_processor_name(processor_name,&namelen);
fprintf(stdout,"Process %d of %d on %s\n",
myid, numprocs, processor_name);
n = 0
if (myid == 0)
{
printf("Please give N=");
scanf(&n);
startwtime = MPI_Wtime();
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);/*将n值广播出去*/
h = 1.0 / (double) n;/*得到矩形的宽度,所有矩形的宽度都相同*/
sum = 0.0; /*给矩形面积赋初值*/
for (i = myid + 1; i <= n; i += numprocs)
/*每一个进程计算一部分矩形的面积若进程总数numprocs为4 将0-1区间划分为100个矩形则各个进程分别计算矩形块
0进程 1 5 9 13 ... 97
1进程 2 6 10 14 ... 98
2进程 3 7 11 15 ... 99
3进程 4 8 12 16 ... 100
*/
{
x = h * ((double)i - 0.5);
sum += f(x);
}
mypi = h * sum;/*各个进程并行计算得到的部分和*/
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0,MPI_COMM_WORLD);
/*将部分和累加得到所有矩形的面积该面积和即为近似π值*/
if (myid == 0)
/*执行累加的0号进程将近似值打印出来*/
{
printf("pi is approximately %.16f, Error is %.16f\n",
pi, fabs(pi - PI25DT));
endwtime = MPI_Wtime();
printf("wall clock time = %f\n", endwtime-startwtime);
fflush( stdout );
}
MPI_Finalize();
}
虽然我没有能独立完成这次编程任务,最后也没有在比赛中获胜,但是这次学习的经历让我认识到了并行计算惊人的处理能力与蕴涵的巨大计算潜能。我的这次小小编程经验只是取了并行计算浩瀚海洋里的浅浅一瓢,但足以让我“醍醐灌顶”好好消化一段时间了。以后,我一定更加注意扩充自己在并行计算方面知识,将并行计算更好的运用到编程中,写出跑的更快的程序来!