OpenMP并行编程
- 什么是OpenMP?
“OpenMP (Open Multi-Processing) is an application programming interface (API) that supports multi-platform shared memory multiprocessing programming in C, C++ and Fortran on many architectures, including Unix and Microsoft Windows platforms. It consists of a set of compiler directives, library routines, and environment variables that influence run-time behavior. ”
简单来说,OpenMP是一个可以应用于多种平台的共享内存式并行计算的接口。 - Openmp的工作模式:
Openmp的工作模式为串行-并行-串行…。一开始的主线程是串行,当在需要并行的时候(这时候程序中应该有相应的Openmp指令语句),多个线程开始一起工作。若当前的并行块结束(仍旧由相应的Opemp指令语句来控制)时,又重新回到单一的主线程。如此可往复继续。在一个四核心cpu上运行Openmp程序(并行块的线程数默认是核心数目,这里即为4个线程),程序处于主线程时cpu利用率为100%,但是当程序进入并行块时所有的核心都会参与进来,cpu利用率会达到400%。如果程序的主要运算部分都处于并行区域,则绝大部分时间cpu都处于400%的工作状态,这样便大大提高cpu的利用率。 - Openmp程序的结构:
正如上面所说,编写Openmp程序只需要在已有的串行程序上稍加修改即可:在并行开始和结束的地方加上Openmp语句引导并行的开始和结束。这些引导语句本身处于注释语句的地位,必须在编译时加上Openmp并行参数才能使其生效。如果不加编译参数,编译出来的程序仍旧是串行程序。
Openmp是最容易实现的并行方式。 - Openmp程序的编写:
下面以fortran语言为例说明Openmp程序的编写(对c语言和fortran语言,都可以参考本文最后给出的openmp教程)。一般的格式为!$omp parallel CLAUSE
!$omp DIRECTION
[ structured block of code ]
!$omp end DIRECTION
!$omp end parallel其中DIRECTION是Openmp指令,有sections,do等,指定并行行为。中间的
[ structured block of code ]
即是需要并线的程序块。除了上面的称为DIRECTION的指令语句外,Openmp还需要称为CLAUSE的从句对并行进行限制和说明。比如,需要对私有变量进行声明时就需要用到private从句(这是经常要遇到的,后面会以例子说明)。在fortran的串行编译下,以“!”打头的都处于屏蔽状态是不起作用的。加了openmp编译参数后才会生效。
我在程序编写中用到最多的是do指令,偶尔用一下sections。do指令通常用来并行化do循环。本来用一个线程来执行的长的do循环被分割成几个部分让多个线程同时执行,这样就节省了时间。sections指令通常用来将前后没有依赖关系的程序块(也即原本不分先后,你换下顺序也无所谓)并行化。因为无关联,所以可以同时执行。
可以说,若程序主要用来做计算,掌握了do和sections这两个指令足矣!
- 简单的程序例子:
1.Sections 指令的应用:!$OMP PARALLEL SHARED(A,B,C), PRIVATE(I) !//Paralell块开始
!$OMP SECTIONS !//Sections开始
!$OMP SECTION !//第一个section
DO I = 1, N/2
C(I) = A(I) + B(I)
END DO
!$OMP SECTION !//第二个section
DO I = 1+N/2, N
C(I) = A(I) + B(I)
END DO
!$OMP END SECTIONS NOWAIT !//Sections结束
!$OMP END PARALLEL !//Paralell块结束这个并行语句将本来从1到N的循环手动分为两个部分并行执行。上面的shared,private就是从句(clause),声明A,B,C为公有的,而循环指标I是私有的。因为两个section同时执行,都会对I进行改变,所以两个section的循环指标必须彼此独立,不能是同一个变量。PRIVATE会自动将这个会引发冲突的变量按需生成多个拷贝以供使用。最后的!$OMP END SECTIONS NOWAIT语句告诉两个线程可各自自行结束,无需相互等待。
2.Do 指令的应用:
上面用Section实现的功能完全可以用Do来实现:!$OMP PARALLEL SHARED(A,B,C), PRIVATE(I) !//Paralell块开始
!$OMP DO !//Do的并行开始
DO I = 1, N
C(I) = A(I) + B(I)
END DO
!$OMP END DO !//Do的并行结束
!$OMP END PARALLEL !//Paralell块结束Do循环本来是从1到N,现在有多少个线程就分为多少个部分执行,比上面的section更方便智能。不用担心循环次数N不能被线程数整除~。一般情况下,各个线程均分循环次数,但是在某些循环指标下运算可能比较快,所以各个线程的运算时间可能不尽相同。这时候如果需要让各个线程都结束了才能再往下(没有NOWAIT),快的线程就必须等待慢的线程。为了解决这个问题需要加上schedule从句,首行变为如下:
!$OMP PARALLEL SHARED(A,B,C), PRIVATE(I),SCHEDULE(DYNAMIC)
这个SCHEDULE(DYNAMIC)从句告诉程序动态调整并线方式,那些任务轻松运算快的线程会自动去帮任务重运算慢的线程,力争所有线程同时完成任务。
关于Do的积累计算,如累加,需要加上REDUCTION从句:
C=0.d0
!$OMP PARALLEL SHARED(A,C), PRIVATE(I),REDUCTION(+:C)
!$OMP DO
DO I = 1, N
C =C+ A(I)
END DO
!$OMP END DO
!$OMP END PARALLEL这里将累加分为几个部分由多个线程进行运算,由于各个线程都在0.d0的基础上开始计算它该算的部分,所以最后必须将各部分计算的结果再次求和。REDUCTION(+:C)从句就实现了这个效果。类似的叠乘等等用类似写法,只需把“:”前的运算符改为乘法“*”即可。
- 一些注意问题:
1.尤其要注意的问题就是变量的私有和公有问题。其实只要把握好一个原则,即如果这个变量有可能会被不同的线程同时进行写操作(这不是你希望看到的),则这个变量就应该声明为私有。一般来说,并行体中临时用到的一些中间变量应该是私有的。2.据我的经验,Fortran中如果不特别声明,变量都是默认公有的。这一点可以用DEFAULT(PRIVATE/SHARED)从句强行改变。循环指标默认是私有的,无需自己另外声明。放在common域中的变量都是全局的,若要将这些全局变量私有化,可使用threadprivate指令(参见文章:OpenMP并行编程:threadprivate指令)。
3.并行引导语句可以简化,但要注意前后配对。比如上面那个累加的例子可以这样写:
C=0.d0
!$OMP PARALLEL DO SHARED(A,C), PRIVATE(I),REDUCTION(+:C)
DO I = 1, N
C =C+ A(I)
END DO
!$OMP END PARALLEL DO也即可以将从句加在指令之后。
4.Fortran+Openmp的编译问题:
一般来说,加上-openmp编译参数即可。如:
ifort -openmp -o exe.out main.f
gfortran用-fopenmp编译参数,g77和ifort一样用-openmp参数。
如果用Makefile,将编译参数放在合适的地方。5.对于多重do循环,如果中间变量太多,对私有公有弄不清楚或者虽然清楚但是闲麻烦,可以保留最外层循环,将里面的循环在别处写成一个子函数或子程序 ,然后在此处调用。这样从结构上看就是对一重循环进行并行化,条理清楚不容易出错。当然,传递给子函数或子程序的参数一般是要声明私有的。
6.将串行程序改为Openmp并行程序后,在加与不加-openmp编译参数的情况下分别编译并运算,比较并行与串行的结果,确保并行块没有改错。
7.可以在并行开始前指定由多少个线程来并行。在单cpu单核心的机器上也可以(虽然没有实际意义,但可以用来调试并行程序):
CALL OMP_SET_NUM_THREADS(scalar_integer_expression)
其中scalar_integer_expression是个整形变量,指定并行的线程数目。
8.Openmp对私有变量的大小有限制。所以当遇到这样的情况,一般就是由这个限制造成的:不加openmp并行时程序没有问题,加了openmp并行时出现断错误(segmentation fault),但是当把某个(一些)私有数组的维数变小时,段错误消失而且和串行时结果一致。
解决办法(linux下,windows下另外search)如下:
在linux终端执行
ulimit -s unlimited ;export KMP_STACKSIZE=2048000
后一个数字参数足够大即可。
OpenMP并行编程的更多相关文章
- OpenMP 并行编程
OpenMP 并行编程 最近开始学习并行编程,目的是为了提高图像处理的运行速度,用的是VS2012自带的OpenMP. 如何让自己的编译器支持OpenMP: 1) 点击 项目属性页 2)点击 配置 3 ...
- OpenMP并行编程应用—加速OpenCV图像拼接算法
OpenMP是一种应用于多处理器程序设计的并行编程处理方案,它提供了对于并行编程的高层抽象.仅仅须要在程序中加入简单的指令,就能够编写高效的并行程序,而不用关心详细的并行实现细节.减少了并行编程的难度 ...
- OpenMP共享内存并行编程详解
实验平台:win7, VS2010 1. 介绍 平行计算机可以简单分为共享内存和分布式内存,共享内存就是多个核心共享一个内存,目前的PC就是这类(不管是只有一个多核CPU还是可以插多个CPU,它们都有 ...
- C++ OpenMp的并行编程
基于OpenMp的并行编程 功能:并行处理比较耗时的for循环 在OpenMP中,对for循环并行化的任务调度使用schedule子句来实现: 使用格式:schedule(type[,size]) t ...
- 【并行计算】基于OpenMP的并行编程
我们目前的计算机都是基于冯偌伊曼结构的,在MIMD作为主要研究对象的系统中,分为两种类型:共享内存系统和分布式内存系统,之前我们介绍的基于MPI方式的并行计算编程是属于分布式内存系统的方式,现在我们研 ...
- 并行编程OpenMP基础及简单示例
OpenMP基本概念 OpenMP是一种用于共享内存并行系统的多线程程序设计方案,支持的编程语言包括C.C++和Fortran.OpenMP提供了对并行算法的高层抽象描述,特别适合在多核CPU机器上的 ...
- 在fortran下进行openmp并行计算编程
最近写水动力的程序,体系太大,必须用并行才能算的动,无奈只好找了并行编程的资料学习了.我想我没有必要在博客里开一个什么并行编程的教程之类,因为网上到处都是,我就随手记点重要的笔记吧.这里主要是open ...
- OpenMP并行程序设计——for循环并行化详解
在C/C++中使用OpenMP优化代码方便又简单,代码中需要并行处理的往往是一些比较耗时的for循环,所以重点介绍一下OpenMP中for循环的应用.个人感觉只要掌握了文中讲的这些就足够了,如果想要学 ...
- Openmp多线程编程练习
环境配置 一般使用Visual Studio2019来作为openmp的编程环境 调试-->属性-->C/C++-->所有选项-->Openmp支持改为 是(可以使用下拉菜单) ...
随机推荐
- Lua和C之间的交互
转自:http://blog.csdn.net/sumoyu/article/details/2592693 (一) Lua 调C函数 什么样类型的函数可以被Lua调用 typedef int ( ...
- ORACLE配置tnsnames.ora文件实例
ORACLE配置tnsnames.ora文件实例客户机为了和服务器连接,必须先和服务器上的监听进程联络.ORACLE通过tnsnames.ora文件中的连接描述符来说明连接信息.一般tnsnames. ...
- mysql的多表查询
转自:http://huaxia524151.iteye.com/blog/1423614 转自:http://blog.sina.com.cn/s/blog_4c197d420101cnm9.htm ...
- HDU 4362 Dragon Ball 贪心DP
Dragon Ball Problem Description Sean has got a Treasure map which shows when and where the dragon ...
- JavaScript案例四:全选练习
JavaScript实现全选,全不选等效果... <!DOCTYPE html> <html> <head> <title>JavaScript全选练习 ...
- WebStorm9
下载地址: http://www.onlinedown.net/soft/554406.htm 注册码: UserName:William===== LICENSE BEGIN =====45550- ...
- hdu2159
#include<bits/stdc++.h> #define MAX 155 using namespace std; struct Node { int exp; int pat; } ...
- JVM的粗略简述
什么是Java虚拟机 虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java虚拟机有自己完善的硬体架构,如处理器.堆栈.寄存器等,还具有相应的指令系统.JVM屏蔽了与 ...
- Lock的基础概念
锁的相关概念 1.可重入锁 如果锁具备可重入性,则称作为可重入锁.像synchronized和ReentrantLock都是可重入锁,可重入性在我看来实际上表明了锁的分配机制:基于线程的分配,而不是基 ...
- OUYA游戏开发核心技术剖析OUYA游戏入门示例——StarterKit
第1章 OUYA游戏入门示例——StarterKit StarterKit是一个多场景的游戏示例,也是OUYA官方推荐给入门开发者分析的第一个完整游戏示例.本章会对StarterKit做详细介绍,包 ...