OpenMP程序设计基础
首先,我们说了OpenMP在Linux下的编译/运行方法
g++ -fopenmp -o hello.o hello.cpp
./hello.o
接着,我们聊到了OpenMP程序结构,与C语言相同,由main函数开始,return 0为结束(整体来看为串行)
我们在串行区,通过编译指导语句#pragma omp parallel [字句] {语句块},来构造并行区
换言之,OpenMP程序结构:
串行→并行→串行
指令parallel构造并行区:(此处开始由多个线程并行执行)
#pragma omp parallel[字句]
{
代码块(此处开始写并行区的代码)
}
当然,我们还可以在构造并行区前,去指定并行区内线程个数。
omp_set_num_threads(8);
OpenMP常用函数
我们可以通过get_wtime来获取系统时间
omp_get_wtime()
如果我们建立两个变量,start_time和end_time,在程序开始时获得start_time,在程序结束时获得end_time,两时间相减就是程序运行时间。
注:如果程序运行时间较短,可以将时间用double类型的变量进行存储。
如果采用int类型,可能会出现0秒(0.8888s)-0秒(0.1024s)=0秒 这种无意义的时间。
并行计算的算法评价-加速比
并行计算能够提高计算性能,对于实际的应用问题,程序员、使用者,最为关心的就是并行程序相对串行程序的执行速度上的差异。换言之,搞并行快了还是慢了,或,加快的倍数—并行加速比(简称加速比)
Rs=ts/tp
加速比的定义:(程序顺序执行的时间)÷(同一结果的程序并行执行的时间)
并行计算的成本
并行计算是有成本的,比如上学时,老师让大家放学做值日,留下的学生越多,成本越高,但成本高了效率并不一定提升。
比如:资源的有限性,笤帚只有1把,同时只能有1个人(主线程)扫地,那剩下99个人(其他线程)只能等着,而且此时,如果你(班主任)强行让100个人大家都要扫地,那结果只能是大家抢夺笤帚,带来结果不可控。
再比方说:事情是有顺序和依赖性的,比如墩地之前需要扫地,扫不干净没法擦地,这时候墩地的同学(线程2)就只能等着扫地的同学(线程1),这时候2个线程并没有提高效率。
因此,我们来总结一下并行计算的开销(也是OpenMP程序设计必须要思考的问题)
(1)线程的建立和销毁、线程间通信、同步带来的开销
(2)为争夺共享资源而引起竞争造成的开销(此时程序运行结果往往随机,结果已经无意义)
(3)各个CPU工作负载分配的不均衡和内存带宽等因素的限制,导致其他线程等待造成的时间开销
这都是并行程序设计需要思考的最基本的问题。
简单的求π值的并行计算程序
我做了一个通过矩阵来模拟一个正方形,通过正方形内的圆面积,来计算π值的程序。
设计了parallel for,并行区内for循环的优化加速、统计运行时间、采取数组来防止写入统一数据造成冲突等
可以参考一个
//写一个并行计算π的程序
//通过定义法来计算π
#include<iostream>
#include<vector>
#include<omp.h>
using namespace std;
int main()
{
cout<<"计算pai程序开始"<<endl;
int i,j;
int tid=4;
double pai;
int lang=3;
int max=10;
int temp[tid];
for(i=0;i<tid;i++)
temp[i]=0;
int temps=0;
for(i=0;i<lang;i++)
max=max*10;
//定义一个二维数组
vector<vector<bool>> array(max);
for (i = 0; i < array.size(); i++)
array[i].resize(max);
//cout<<"计算pai程序开始"<<endl;
omp_set_num_threads(tid);
double start_time,end_time;
start_time=omp_get_wtime(); //获取当前时间
#pragma omp parallel shared(i,j,max,array,temp)
{
#pragma omp for
for(int i=0;i<max;i++){
for(int j=0;j<max;j++){
int tid=omp_get_thread_num();
if(i*i+j*j>max*max){
array[i][j]=0;
}
else{
array[i][j]=1;
temp[tid]++;
}
}
}
}
for(i=0;i<tid;i++){
temps=temps+temp[i];
}
pai=(4.0*temps)/(max*max);
end_time=omp_get_wtime();
cout<<"pai="<<pai<<endl;
cout<<"time="<<end_time-start_time<<"s"<<endl;
return 0;
}
这个程序采用矩阵去模拟,空间开销很大,计算精度不高。但是模拟的非常直观,方阵=正方形
后续还有许多效率可以提升的地方,欢迎拍砖!