OpenMP的学习
这些天接触到了一个新的概念,并行计算,概念新了点,不过思想日常生活中比比皆是,通俗的说也就是大家一起同时做某个事情,说学习就学习,昨天我就登了一下OpenMP的官方网站,找到一篇“A Hands-On Introduction to OpenMP ” 大家可以直接下载,这个对于入门还是一个很好的选择,然后看了下编辑器Compilers,很好的是在VS2008上直接可以使用,于是乎,开始测试一下OpenMP的神奇,于是乎根据上面的介绍写了一个Hello World的程序
#include <stdio.h> #include <omp.h> int main() { #pragma omp parallel { int ID = omp_get_thread_num(); printf("hello(%d) ", ID); printf("world(%d) \n", ID); } } 没反应,既然还就是只出现了
hello(0) world(0)
请按任意键继续. . .
想想我的电脑也是双核的,跟展示的四核的不一样,也不至于是一个吧,估计那个地方不对,查了下原来在语言中要选择OpenMP支持
好的不错 出现了
hello(0) hello(1) worl
world(1)
请按任意键继续. . .
这个结果,看来程序是可以并行了,下面就来了,这是一个简简单单的一个HelloWorld,复杂的怎么搞了,最起码要把基本的函数库要看一下吧
看看能不能找到,到网上查了查,官方提供一个,3百多页,纯英文,英语太差,看看有没有翻译好的,找了找,发现周伟明老师的博客中很有多关于这方面的介绍,慢慢看了下。大致了解了下,再接再厉,也要搞点东西。
那就试一试,看看并行计算到底快多少,于是先做一个并行求和。在这之前先写了串行的试试
#include <stdio.h> #include<time.h> #define N 100000000 void main() { int sum=0; clock_t t1 = clock(); for(int i=0;i<N;i++) { sum +=i; } clock_t t2 = clock(); printf("time=%d",t2-t1); }
time=453请按任意键继续. . .
在对于加法,乘法运算可结合,可交换。对于并行计算,我们一开始也是要找到独立计算,然后再将这些独立计算重新组织成并行代码,一般就是两种组织方式,就是任务分解,一种就是数据分解,我想这个也很直观,而对于这个求和的话,分解任务的话,感觉不可能,想想看sum的值依赖于之前sum上执行的加法运算,这也就是任务之间存在在依赖,存在依赖的话就会可能存在数据竞争,这个也就是我们要避免的。
然后想一想数据分解,程序如下
#include<stdio.h> #include<omp.h> #define N 100000000 void main() { int * x;//开辟数组空间 x=new int[N];//这边分配的空间 int sum=0; double start,end; //初始化数组 int i=0; for (i=0;i<N;i++) { x[i]=i; } start = omp_get_wtime(); #pragma omp parallel for reduction(+:sum) for (int i=0;i<N;i++) { sum=sum+x[i]; } end = omp_get_wtime(); printf("time: %f \n", end - start); }
结果显示:
time: 0.352276
请按任意键继续. . .
时间是快了一点。。。
这边用了reduction,reduction子句将确保每个线程得到的sum保存为一个副本,再一次的叠加,我以N=10为例
#include<stdio.h> #include<omp.h> #define N 10 void main() { int * x;//开辟数组空间 x=new int[N];//这边分配的空间 int sum=0; double start,end; //初始化数组 int i=0; for (i=0;i<N;i++) { x[i]=i; } start = omp_get_wtime(); #pragma omp parallel for reduction(+:sum) for (int i=0;i<N;i++) { printf("Num:%d %d+%d=%d\n",omp_get_thread_num(),sum,x[i],sum+x[i]); sum=sum+x[i]; } printf("sum=%d\n",sum); end = omp_get_wtime(); printf("time: %f \n", end - start); }
显示结果
Num:0 0+0=0
Num:1 0+5=5
Num:0 0+1=1
Num:1 5+6=11
Num:0 1+2=3
Num:1 11+7=18
Num:0 3+3=6
Num:1 18+8=26
Num:0 6+4=10
Num:1 26+9=35
sum=45
time: 0.001591
请按任意键继续. . .
最终等所有的线程执行完之后,reduction子句会将算到的部分加起来10+35=45(这个就是通过(+:sum)中的加号运算符)
我们来测试一下去掉reduction之句会有什么效果代码如下:
#include<stdio.h> #include<omp.h> #define N 10 void main() { int * x;//开辟数组空间 x=new int[N];//这边分配的空间 int sum=0; double start,end; //初始化数组 int i=0; for (i=0;i<N;i++) { x[i]=i; } start = omp_get_wtime(); #pragma omp parallel for //reduction(+:sum) for (int i=0;i<N;i++) { printf("Num:%d %d+%d=%d\n",omp_get_thread_num(),sum,x[i],sum+x[i]); sum=sum+x[i]; } printf("sum=%d\n",sum); end = omp_get_wtime(); printf("time: %f \n", end - start); }
显示结果如下:
Num:0 0+0=0
Num:1 0+5=5
Num:0 0+1=1
Num:1 5+6=11
Num:0 6+2=8
Num:1 12+7=19
Num:0 14+3=17
Num:1 21+8=29
Num:0 24+4=28
Num:1 32+9=41
sum=45
time: 0.001677
请按任意键继续. . .
再执行一遍显示结果如下:
Num:0 0+0=0
Num:1 0+5=5
Num:1 5+6=11
Num:1 11+7=18
Num:1 18+8=26
Num:1 26+9=35
Num:0 35+1=36
Num:0 36+2=38
Num:0 38+3=41
Num:0 41+4=45
sum=45
time: 0.001965
请按任意键继续. . .
虽然结果都是正确,但是极有可能出现错误,两个执行结果不是相同的方式,具体参考了
http://www.cnblogs.com/me115/archive/2011/01/27/1946129.html
OK,先了解了个大概,下面慢慢学习。。。