OpenMP的简单使用教程

转自:http://binglispace.com/2015/01/09/openmp-intro/

OpenMP的简单使用教程

今天有幸参加了一个XSEDE OpenMP的workshop讲座,真是受益匪浅啊。简单来说OpenMP就是一个多线程程序的框架。和MPI相比,MPI每一个Node都有独立的内存空间,但是OpenMP所有的线程共享一个内存空间。显而易见,OpenMP的硬件制约要比MPI大,但是只要硬件跟得上就会比MPI要快。OpenMP一般都会部署再超级计算机中心,但是几年之前它就成为了一个通用标准。基本上所有的主流C/C++语言编译器都支持OpenMP(当然除了C之外,OpenMP还支持Fortran,不过这里我主要介绍一下C),这意味着只要你的计算机上安装了C的编译器你就可以直接使用OpenMP不需要额外部署任何东西。(这太方便了,想想Hadoop,当年为了部署它,我被折磨的那个叫一个销魂啊。)

##编写OpenMP程序

编写OpenMP的程序并不需要额外的学习很多东西,其实就是普通的C代码加上一些Directives。用Hello World为例:

#include<stdio.h>
int main(int argc,char** argv){
  printf("Hello World!\n");
  return 0;
}

这是一个最简单的程序,编译执行后的输出是。

Hello World!

然后我们给他加上OpenMP的directive,他就变成了。

#include<stdio.h>
int main(int argc,char** argv){
  #pragma omp parallel
  printf("Hello World!\n");
  return 0;
}

看到没?就是简单的加了一句话#pragma omp parallel,若是正常编译的话,这句话会被忽略一点都不影响你的程序,只有调用OpenMP的lib编译的时候才会编译成OpenMP的版本。以GCC为例,OpenMP的编译方法是:

gcc -o hello hello.c -fopenmp

仅仅多了一个-fopenmp的flag,太简单了。现在我们试试效果,这个hello world的输出结果变成了:

Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

输出了8次Hello World!。这是为什么呢?原因是那个directive之后的代码被多线程操作了,默认情况下GCC-fopenmpflag会调用和你CPU内核数相同数量的线程来执行程序。这个线程数量是可以控制,只需要修改环境变量中OMP_NUM_THREADS参数,例如:

export OMP_NUM_THREADS=2

之后也不需要重新编译,直接执行之前的程序,就会发现Hello World!的数量变成了两个了。

###for循环

大多数情况下,我们主要会将多线程技术应用在循环中而不是全部代码。OpenMP主要被应用于for循环的多线程处理,这主要还是因为for循环比较容易控制。当然如果你非要用在while循环上也不是不可以,只不过要大量修改你的代码然后用一个block来圈在while之外,总之是一个比较另类的操作了。我在此就不多说了。用一个最简单的例子,找寻1到10000中最大的数字。当然这个例子很白痴,但是代码简洁比较好理解。

#include<stdio.h>
int main(int argc, char** argv){
  int i;
  int max = 0;
  #pragma omp parallel for
  for(i=0;i<=10000;i++){
    if(i>max)max=i;
  }
  printf("%d\n",max);
}

结果是:

10000

我们在directive里面加了一个for,变成了#pragma omp parallel for,这样的话OpenMP就只会把下面的for循环进行多线程处理,所以我们只看到了一个输出而不是好几个。

这里有一点一定要主要,将要进行多线程处理的for循环一定是独立的(independent),也就是说下面这种情况是不可以的。

for(i=0;i<10000;i++){
  a[i] = a[i-1]+1;
}

每一次循环都需要之前的结果,这种循环没有办法进行多线程处理,因为每一次都要等待之前的输出,强行处理还会出错。

####private参数

细心的话,也许你会有一个问题。那就是循环只有一个迭代器(通常是变量i),但进行多线程处理的时候,这个迭代器会不会被各个线程互相扯皮?这却是是一个问题,如果这个迭代器仅仅用作计数的话可能还不是什么大问题,但是如果这个变量也参与运算,这就麻烦了,所有OpenMP引入了private参数,用来告诉编译器那些变量需要有一个本地的实例。这个参数用于迭代器的话就变成了下面的例子。

#pragma omp parallel for private(i)
for(i=0;i<10000;i++){
  ...
}

这样的话每个线程都有自己的i拷贝,就不会冲突了。当然这个参数的用途很广,这仅仅是一个简单的例子。但事实上基本上每次对循环进行多线程处理的时候都需要拷贝迭代器,因此可以把for private()这样连起来记忆,不容易忘。

####reduction参数

我们回到之前的那个10000以内最大整数的例子。之前我提到了循环一定不能互相关联,否则不是效率低下(还不如单线程),就是出错误。这个例子其实就是一个反面典型,就是因为max这个变量。循环的每一步都会读取之前的结果来参与计算。可是针对max变量的这个例子,我们还是有解决办法的。

如果我们环境变量设置线程数为2,这个循环的前5000项和后5000项将分别在两个不同的线程中处理,也就是一份为二。我们需要的是所有数值中的最大值,换一个角度想。我们可以在前5000项和后5000项分别算出最大值,然后在对这两个结果进行比较取最大值,这样的话我们同样完成了寻找最大值的目的同时还可以多线程处理。

那么怎样做到呢?这个时候我们就需要reduction这个参数。reduction就是让某些变量先在各自的线程中独自计算,然后在循环结束时在合并。那么我们用这个参数来修改之前的例子:

#include<stdio.h>
int main(int argc, char** argv){
  int i;
  int max = 0;
  #pragma omp parallel for private(i) reduction(max:max)
  for(i=0;i<=10000;i++){
    if(i>max)max=i;
  }
  printf("%d\n",max);
}

这下就变成了完整版。reduction这个函数格式是reduction(operation:variable),冒号前面的是操作类型,冒号后面的是变量名。目前reduction这个函数只支持如下几个操作:

  • +(初始值是0)
  • -(初始值是0)
  • max(初始值是最小值)
  • min(初始值是最大值)
  • Bit(&,|,^,iand,ior)(初始值是~0,0)
  • Logical(&&,||,.and.,.or.)(初始值是0,1,.true.,.false.)

##编译与执行

其实之前已经提到了如何编译和执行。今天有幸在超计算机中心的服务器上面测试了几次,然后回到本地计算机试了一下,发现本地执行简单的多。因为本地执行就是简单的./program。Windows下的话你可以试试双击。在服务器上面跑还要考虑调度多少node和多少core,但是在本地不需要提供任何额外的参数就和执行普通程序一样。所以说OpenMP真是多线程计算一大神器啊,主要还是操作简单。

之前提到了现在主流的C/C++编译器都已经支持OpenMP了,那么都有那些编译器呢?我在这里给出一个列表。

编译器 参数 不设置环境变量时的初始值
GNU (gcc, g++, gfortran) -fopenmp 与CPU内核数相同数量的线程
Intel (icc ifort) -openmp 与CPU内核数相同数量的线程
Portland Group (pgcc,pgCC,pgf77,pgf90) -mp 只使用一个线程

顺便在提一下,环境变量是控制线程数的环境变量是OMP_NUM_THREADS

###参考文献

时间: 2024-10-26 03:57:34

OpenMP的简单使用教程的相关文章

程序员,一起玩转GitHub版本控制,超简单入门教程 干货2

本GitHub教程旨在能够帮助大家快速入门学习使用GitHub,进行版本控制.帮助大家摆脱命令行工具,简单快速的使用GitHub. 做全栈攻城狮-写代码也要读书,爱全栈,更爱生活. 更多原创教程请关注头条号.每日更新.也可以添加小编微信:fullstackCourse.一起交流,获取最新全栈教程信息.因为FQ原因,不能下载客户端的同仁,可以关注后回复“GitHub客户端”获取安装软件. 上篇教程:GitHub这么火,程序员你不学学吗? 超简单入门教程 干货 GitHub概念部分出现了一丝纰漏.为

spring4.0.6最新稳定版新特性学习,简单学习教程(一)

Spring Framework 4.0 学习整理. Spring框架的核心部分就是Ioc容器,而Ioc控制的就是各种Bean,一个Spring项目的水平往往从其XML配置文件内容就能略知一二,很多项目,往往是外包公司的项目,配置文件往往是乱七八糟,抱着能跑就行,不报错就行的态度去写,然后在项目中后期发现各种缺失又去一通乱补,其结果就是,整个文档可读性极差,毫无章法.这也不能怪写这个XML的人,拿着苦逼程序员的工资干着架构师的工作必然是这个结果.为了程序员的幸福,我认为有必要来一套简单快速的官方

iBatis简单入门教程

iBatis 简介: iBatis 是apache 的一个开源项目,一个O/R Mapping 解决方案,iBatis 最大的特点就是小巧,上手很快.如果不需要太多复杂的功能,iBatis 是能够满足你的要求又足够灵活的最简单的解决方案,现在的iBatis 已经改名为Mybatis 了. 官网为:http://www.mybatis.org/ 搭建iBatis 开发环境: 1 .导入相关的jar 包,ibatis-2.3.0.677.jar .mysql-connector-java-5.1.6

Swift简单入门教程:30分钟玩转Swift

通常来说,编程语言教程中的第一个程序应该在屏幕上打印“Hello, world”.在 Swift 中,可以用一行代码实现:    println("hello, world") 如果你写过 C 或者 Objective-C 代码,那你应该很熟悉这种形式——在 Swift 中,这行代码就是一个完整的程序.你不需要为了输入输出或者字符串处理导入一个单独的库.全局作用域中的代码会被自动当做程序的入口点,所以你也不需要main函数.你同样不需要在每个语句结尾写上分号. 这个教程会通过一系列编程

github简单使用教程

github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就是代码要公开.对于一般人来说公共仓库就已经足够了,而且我们也没多少代码来管理,O(∩_∩)O~.下面是我总结的一些简单使用方法,供初学者参考. ~~廖雪峰老师关于git的教程写得很好,可以百度来看看 1.注册账户以及创建仓库 要想使用github第一步当然是注册github账号了.之后就可以创建仓库了(免费用户只能建公共仓库),Create a New Repository,填好名称后Cr

knockout简单实用教程3

在之前的文章里面介绍了一些KO的基本用法.包括基本的绑定方式,基本的ko的绑定语法包括text绑定,html绑定等等(如有不明请参照上两篇文章),下面呢介绍一下关于ko的其他方面的知识.包括比较特殊绑定方式和语法还有KO官方mapping插件的使用等等.对了在前面的文章中好像漏掉了属性绑定的的介绍.那就先简单介绍下.属性绑定吧.直接上代码. <a data-bind="attr: { href: url, title: details }"> Report </a&g

IOS游戏源码下载之简易版雷电(2.2.3版本)源码完整下载和简单开发教程

 头回写教程这玩意,真不知道要写些什么,所以主要就是共享下我的代码,和一些重要功能的讲解吧,各位如果有啥不懂的可以回帖提问哟. 其实这个demo(为何叫demo呢,因为我真不敢称这个为游戏呀)是我初学cocos2d-x两周的时候写的,所以可能写的不是很好(好吧,其实现在写的东西也不好),当初主要还是靠着度娘和TestCpp学的,所以在此还是要强调一下TestCpp的重要性,要好好把它看一遍哟,以后你想实现什么功能就可以去翻看了. 好了,言归正传,还是介绍下我写的这个demo了,在此先华丽丽的

(转载)github简单使用教程

github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就是代码要公开.对于一般人来说公共仓库就已经足够了,而且我们也没多少代码来管理,O(∩_∩)O~.下面是我总结的一些简单使用方法,供初学者参考. 1.注册账户以及创建仓库 要想使用github第一步当然是注册github账号了.之后就可以创建仓库了(免费用户只能建公共仓库),Create a New Repository,填好名称后Create,之后会出现一些仓库的配置信息,这也是一个git

GitHub这么火,程序员你不学学吗? 超简单入门教程 【转载】

本GitHub教程旨在能够帮助大家快速入门学习使用GitHub. 本文章由做全栈攻城狮-写代码也要读书,爱全栈,更爱生活.原创.如有转载,请注明出处. GitHub是什么? GitHub首先是个分布式的版本控制库.通过使用git,可以方便的记录代码版本. 因国内外大量著名的项目,都开始搬迁到github.它又可以称为开源代码社区. github还是学习的好地方,学习优秀的代码. 可对其他项目中有bug的地方进行改进提交,集合众人的力量促进软件的优化改善. github何其火热,截至2015年2月