openMP多线程编程
2014-12-01 13:36
267 查看
OpenMP(Open Muti-Processing)
OpenMP缺点:
1:作为高层抽象,OpenMp并不适合需要复杂的线程间同步和互斥的场合;
2:另一个缺点是不能在非共享内存系统(如计算机集群)上使用。在这样的系统上,MPI使用较多。
关于openMP实现 临界区 与互斥锁 可参考 reference3
基本使用:
在visual C++2010中使用OpenMP
1:将 Project 的Properties中C/C++里Language的OpenMP Support开启(参数为 /openmp);
2:在编写使用OpenMP 的程序时,则需要先include OpenMP的头文件:omp.h;
3:在要并行化的for循环前面加上 #pragma omp parallel for
如下简单例子:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,
(我的笔记本为2核 4线程)
显示结果为:
0,12,4,8,1,13,5,9,2,14,6,10,3,15,7,11,
OpenMP将循环0-15拆分成0-3,4-7,8-11,12-15四个部分来执行。
当编译器发现#pragma omp parallel for后,自动将下面的for循环分成N份,(N为电脑CPU线程数),然后把每份指派给一个线程去执行,而且多线程之间为并行执行。
关于获取CPU核数与线程ID
Hands on FAQ:
*怎么在Linux上运行OpenMP程序?
> 只需要安装支持OpenMP的编译器即可,比如GCC 4.2以上版本(好像Fedora Core带的部分4.1版本也支持),或者ICC(我用的version 9.1是支持的,其他没试过)。
*怎么缺点编译器是不是支持OpenMP?
> 看编译器安装路径下/include目录里有没有omp.h。
*怎么区分OpenMP程序?
> 程序中有没有以下内容:
> #include <omp.h>
> #pragma omp ...
*怎么编译OpenMP程序?
> gcc -fopenmp [sourcefile] -o [destination file]
> icc -openmp [sourcefile] -o [destination file]
*怎么运行OpenMP程序?
> 编译后得到的文件和普通可执行文件一样可以直接执行。
*怎么设置线程数?
>:在程序中写入set_num_threads(n);
> Method2:export OMP_NUM_THREADS=n;
> 两种方法各有用处,前者只对该程序有效,后者不用重新编译就可以修改线程数。
Example1:并行与串行时间差别
Sequetial Version:
Parallel Version:
Result:
Sequential version:
Parallel version:
------------------------------------------------------------------------------------------------------------------------------------------------------------
Example2:矩阵拟合法计算Pi
Sequential Version:
Parallel Version:
我的电脑为2核,4线程 提升速度为13433/3739=3.6 。因为这个程序本身具有良好的并发性,循环间几乎没有数据依赖,除了sum,但是用reduction(+:sum)把对于sum的相关也消除了。
关于reduction , private具体请到references 7中查看。
需要特别注意的一点是:
上述的计时方法使用的是gettimeofday() 而原博客给出的计时方法是time_t (使用time_t是没法达到作者所说的速度的,你会发现 并行的时间比串行还慢)。
主要原因:计时方法不一样,具体请看两者的区别(另一篇博客)
reference:
1:http://baike.baidu.com/view/1687659.htm
2:/article/5664459.html
-----------------------------------------------------------------------------------------------------------------
3:http://www.ibm.com/developerworks/cn/aix/library/au-aix-openmp-framework/index.html
4:http://openmp.org/wp/openmp-compilers/(官网)
5:http://blog.163.com/zl_dream1106/blog/static/84286020105210012295/ (linux 系统中OpenMP)
6:http://blog.163.com/zl_dream1106/blog/static/842860201052952352/?suggestedreading&wumii(OpenMP编程指南)
7:http://blog.163.com/zl_dream1106/blog/static/84286020105293213869/?suggestedreading&wumii(OpenMP
入门)
OpenMP缺点:
1:作为高层抽象,OpenMp并不适合需要复杂的线程间同步和互斥的场合;
2:另一个缺点是不能在非共享内存系统(如计算机集群)上使用。在这样的系统上,MPI使用较多。
关于openMP实现 临界区 与互斥锁 可参考 reference3
windows系统下使用
==========================WINDOWS系统中使用==========================基本使用:
在visual C++2010中使用OpenMP
1:将 Project 的Properties中C/C++里Language的OpenMP Support开启(参数为 /openmp);
2:在编写使用OpenMP 的程序时,则需要先include OpenMP的头文件:omp.h;
3:在要并行化的for循环前面加上 #pragma omp parallel for
如下简单例子:
//未使用OpenMP #include <stdio.h> #include <stdlib.h> void Test(int n) { for(int i = 0; i < 10000; ++i) { //do nothing, just waste time } printf("%d, ", n); } int main(int argc,char* argv[]) { for(int i = 0; i < 16; ++i) Test(i); system("pause"); }结果为:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,
//使用OpenMP <pre name="code" class="cpp">#include <stdio.h> #include <stdlib.h> #include <omp.h> void Test(int n) { for(int i = 0; i < 10000; ++i) { //do nothing, just waste time } printf("%d, ", n); } int main(int argc,char* argv[]) { #pragma omp parallel for for(int i = 0; i < 16; ++i) Test(i); system("pause"); }
(我的笔记本为2核 4线程)
显示结果为:
0,12,4,8,1,13,5,9,2,14,6,10,3,15,7,11,
OpenMP将循环0-15拆分成0-3,4-7,8-11,12-15四个部分来执行。
当编译器发现#pragma omp parallel for后,自动将下面的for循环分成N份,(N为电脑CPU线程数),然后把每份指派给一个线程去执行,而且多线程之间为并行执行。
关于获取CPU核数与线程ID
#include <iostream> #include <omp.h> int main(){ int sum = 0; int a[10] = {1,2,3,4,5,6,7,8,9,10}; int coreNum = omp_get_num_procs();//获得处理器个数(其实获取的是线程的数量,我的笔记本为2核4线程,测试时获取的数字为4)</span> int* sumArray = new int[coreNum];//对应处理器个数,先生成一个数组 for (int i=0;i<coreNum;i++)//将数组各元素初始化为0 sumArray[i] = 0; #pragma omp parallel for for (int i=0;i<10;i++) { int k = <span style="color:#3366FF;">omp_get_thread_num();//获得每个线程的ID</span> sumArray[k] = sumArray[k]+a[i]; } for (int i = 0;i<coreNum;i++) sum = sum + sumArray[i]; std::cout<<"sum: "<<sum<<std::endl; return 0; }
Ubuntu系统中使用
=================ubuntu系统中=====================================Hands on FAQ:
*怎么在Linux上运行OpenMP程序?
> 只需要安装支持OpenMP的编译器即可,比如GCC 4.2以上版本(好像Fedora Core带的部分4.1版本也支持),或者ICC(我用的version 9.1是支持的,其他没试过)。
*怎么缺点编译器是不是支持OpenMP?
> 看编译器安装路径下/include目录里有没有omp.h。
*怎么区分OpenMP程序?
> 程序中有没有以下内容:
> #include <omp.h>
> #pragma omp ...
*怎么编译OpenMP程序?
> gcc -fopenmp [sourcefile] -o [destination file]
> icc -openmp [sourcefile] -o [destination file]
*怎么运行OpenMP程序?
> 编译后得到的文件和普通可执行文件一样可以直接执行。
*怎么设置线程数?
>:在程序中写入set_num_threads(n);
> Method2:export OMP_NUM_THREADS=n;
> 两种方法各有用处,前者只对该程序有效,后者不用重新编译就可以修改线程数。
Example1:并行与串行时间差别
Sequetial Version:
#include<iostream> #include<sys/time.h> #include<unistd.h> using namespace std; void test(int n) { int a=0; struct timeval tstart,tend; double timeUsed; gettimeofday(&tstart,NULL); for(int i=0;i<1000000000;i++) { a=i+1; } gettimeofday(&tend,NULL); timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec; cout<<n<<" Time="<<timeUsed/1000<<" ms"<<endl; } int main() { struct timeval tstart,tend; double timeUsed; gettimeofday(&tstart,NULL); int j=0; for(j=0;j<4;j++) { test(j); } gettimeofday(&tend,NULL); timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec; cout<<" Total Time="<<timeUsed/1000<<" ms"<<endl; return 0; }
Parallel Version:
#include<iostream> #include<sys/time.h> #include<unistd.h> #include<omp.h> using namespace std; void test(int n) { int a=0; struct timeval tstart,tend; double timeUsed; gettimeofday(&tstart,NULL); for(int i=0;i<1000000000;i++) { a=i+1; } gettimeofday(&tend,NULL); timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec; cout<<n<<" Time="<<timeUsed/1000<<" ms"<<endl; } int main() { struct timeval tstart,tend; double timeUsed; gettimeofday(&tstart,NULL); int j=0; #pragma omp parallel for for(j=0;j<4;j++) { test(j); } gettimeofday(&tend,NULL); timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec; cout<<" Total Time="<<timeUsed/1000<<" ms"<<endl; return 0; }
Result:
Sequential version:
0 Time=2064.69 ms 1 Time=2061.11 ms 2 Time=2076.32 ms 3 Time=2077.93 ms Total Time=8280.14 ms
Parallel version:
2 Time=2148.22 ms 3 Time=2151.72 ms 0 Time=2151.85 ms 1 Time=2151.77 ms Total Time=2158.81 ms
------------------------------------------------------------------------------------------------------------------------------------------------------------
Example2:矩阵拟合法计算Pi
Sequential Version:
#include<iostream> #include<sys/time.h> #include<unistd.h> //#include <omp.h> using namespace std; int main () { struct timeval tstart,tend; double timeUsed; static long num_steps =1000000000; double step; int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; gettimeofday(&tstart,NULL); //#pragma omp parallel for reduction(+:sum) private(x) /*只加了这一句,其他不变*/ for (i=0;i < num_steps; i++) { x = (i+0.5)*step; sum = sum + 4.0/(1.0+x*x); } pi = step * sum; gettimeofday(&tend,NULL); timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec; timeUsed=timeUsed/1000; cout<<"pi="<<pi<<" ("<<num_steps<<" ) "<<timeUsed<<" ms"<<endl; return 0; }
Parallel Version:
#include<iostream> #include<sys/time.h> #include<unistd.h> #include <omp.h> using namespace std; int main () { struct timeval tstart,tend; double timeUsed; static long num_steps = 1000000000; double step; int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; gettimeofday(&tstart,NULL); #pragma omp parallel for reduction(+:sum) private(x) /*只加了这一句,其他不变*/ for (i=0;i < num_steps; i++) { x = (i+0.5)*step; sum = sum + 4.0/(1.0+x*x); } pi = step * sum; gettimeofday(&tend,NULL); timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec; timeUsed=timeUsed/1000; cout<<"pi="<<pi<<" ("<<num_steps<<" ) "<<timeUsed<<" ms"<<endl; return 0; }运行结果为:
von@von-pc:~/test$ ./parrPI2 pi=3.14159 (1000000000 ) 3729.68 ms von@von-pc:~/test$ ./seqPI2 pi=3.14159 (1000000000 ) 13433.1 ms
我的电脑为2核,4线程 提升速度为13433/3739=3.6 。因为这个程序本身具有良好的并发性,循环间几乎没有数据依赖,除了sum,但是用reduction(+:sum)把对于sum的相关也消除了。
关于reduction , private具体请到references 7中查看。
需要特别注意的一点是:
上述的计时方法使用的是gettimeofday() 而原博客给出的计时方法是time_t (使用time_t是没法达到作者所说的速度的,你会发现 并行的时间比串行还慢)。
主要原因:计时方法不一样,具体请看两者的区别(另一篇博客)
reference:
1:http://baike.baidu.com/view/1687659.htm
2:/article/5664459.html
-----------------------------------------------------------------------------------------------------------------
3:http://www.ibm.com/developerworks/cn/aix/library/au-aix-openmp-framework/index.html
4:http://openmp.org/wp/openmp-compilers/(官网)
5:http://blog.163.com/zl_dream1106/blog/static/84286020105210012295/ (linux 系统中OpenMP)
6:http://blog.163.com/zl_dream1106/blog/static/842860201052952352/?suggestedreading&wumii(OpenMP编程指南)
7:http://blog.163.com/zl_dream1106/blog/static/84286020105293213869/?suggestedreading&wumii(OpenMP
入门)
相关文章推荐
- openMP多线程编程
- 在C++中使用openmp进行多线程编程
- Linux环境下的OpenMP多线程编程
- OpenMP 编程实例(蒙特卡罗算法)
- Caffe:CPU模式下使用openblas-openmp(多线程版本)
- java多线程编程
- 《多线程编程》学习之六:String的常量池特性,锁对象的改变,volatile关键字
- 在CodeBlocks上配置OpenMP
- 一起来学OpenMP(1)——初体验
- 多线程编程
- Python核心编程:第18章 多线程编程
- Java多线程编程中Future模式的详解<转>
- C语言使用pthread多线程编程(windows系统)
- Qt编写OpenMP程序--HelloWorld
- Java 多线程编程
- 通过 GCC 学习 OpenMP 框架
- OpenMP并行程序设计之OpenMP使用入门
- Qt C++ 并发,并行,多线程编程系列1 什么是并发
- [我眼中的C#]多线程编程
- OpenMP在ARM-Linux以及NDK中的编译和使用