zoukankan      html  css  js  c++  java
  • openMP多线程编程

    OpenMP(Open Muti-Processing) 

    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

    如下简单例子:

    [cpp] view plain copy
     
    1. //未使用OpenMP  
    2. #include <stdio.h>  
    3. #include <stdlib.h>  
    4.   
    5. void Test(int n) {  
    6. for(int i = 0; i < 10000; ++i)   
    7. {  
    8.       //do nothing, just waste time  
    9. }  
    10.     printf("%d, ", n);  
    11. }  
    12.   
    13. int main(int argc,char* argv[])   
    14. {  
    15.     for(int i = 0; i < 16; ++i)  
    16.     Test(i);  
    17.     system("pause");  
    18. }  

    结果为:

    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,

    [cpp] view plain copy
     
    1. //使用OpenMP  
    2. <pre name="code" class="cpp">#include <stdio.h>  
    3. #include <stdlib.h>  
    4. #include <omp.h>  
    5.   
    6. void Test(int n) {  
    7. for(int i = 0; i < 10000; ++i) {  
    8. //do nothing, just waste time  
    9. }  
    10.     printf("%d, ", n);  
    11. }  
    12.   
    13. int main(int argc,char* argv[])   
    14. {  
    15. #pragma omp parallel for  
    16.     for(int i = 0; i < 16; ++i)  
    17.     Test(i);  
    18.     system("pause");  
    19. }  
    
    

    (我的笔记本为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

    [cpp] view plain copy
     
    1. #include <iostream>  
    2. #include <omp.h>  
    3. int main(){  
    4.     int sum = 0;  
    5.     int a[10] = {1,2,3,4,5,6,7,8,9,10};  
    6.     int coreNum = omp_get_num_procs();//获得处理器个数(其实获取的是线程的数量,我的笔记本为2核4线程,测试时获取的数字为4)</span>  
    7.     int* sumArray = new int[coreNum];//对应处理器个数,先生成一个数组  
    8.     for (int i=0;i<coreNum;i++)//将数组各元素初始化为0  
    9.         sumArray[i] = 0;  
    10. #pragma omp parallel for  
    11.     for (int i=0;i<10;i++)  
    12.     {  
    13.         int k = <span style="color:#3366FF;">omp_get_thread_num();//获得每个线程的ID</span>  
    14.         sumArray[k] = sumArray[k]+a[i];  
    15.     }  
    16.     for (int i = 0;i<coreNum;i++)  
    17.         sum = sum + sumArray[i];  
    18.     std::cout<<"sum: "<<sum<<std::endl;  
    19.     return 0;  
    20. }  

    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:

    [cpp] view plain copy
     
    1. #include<iostream>  
    2. #include<sys/time.h>  
    3. #include<unistd.h>  
    4.   
    5. using namespace std;  
    6.   
    7. void test(int n)  
    8. {     
    9.     int a=0;  
    10.     struct timeval tstart,tend;  
    11.     double timeUsed;  
    12.     gettimeofday(&tstart,NULL);  
    13.     for(int i=0;i<1000000000;i++)  
    14.     {  
    15.         a=i+1;  
    16.     }  
    17.     gettimeofday(&tend,NULL);  
    18.     timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec;  
    19.     cout<<n<<" Time="<<timeUsed/1000<<" ms"<<endl;  
    20. }  
    21. int main()  
    22. {  
    23.     struct timeval tstart,tend;  
    24.     double timeUsed;  
    25.     gettimeofday(&tstart,NULL);  
    26.     int j=0;  
    27.     for(j=0;j<4;j++)  
    28.     {  
    29.         test(j);  
    30.     }  
    31.     gettimeofday(&tend,NULL);  
    32.     timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec;  
    33.     cout<<" Total Time="<<timeUsed/1000<<" ms"<<endl;  
    34.     return 0;  
    35. }  


    Parallel Version:

    [cpp] view plain copy
     
    1. #include<iostream>  
    2. #include<sys/time.h>  
    3. #include<unistd.h>  
    4. #include<omp.h>  
    5.   
    6. using namespace std;  
    7.   
    8. void test(int n)  
    9. {     
    10.     int a=0;  
    11.     struct timeval tstart,tend;  
    12.     double timeUsed;  
    13.     gettimeofday(&tstart,NULL);  
    14.     for(int i=0;i<1000000000;i++)  
    15.     {  
    16.         a=i+1;  
    17.     }  
    18.     gettimeofday(&tend,NULL);  
    19.     timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec;  
    20.     cout<<n<<" Time="<<timeUsed/1000<<" ms"<<endl;  
    21. }  
    22. int main()  
    23. {  
    24.     struct timeval tstart,tend;  
    25.     double timeUsed;  
    26.     gettimeofday(&tstart,NULL);  
    27.     int j=0;  
    28. #pragma omp parallel for  
    29.     for(j=0;j<4;j++)  
    30.     {  
    31.         test(j);  
    32.     }  
    33.     gettimeofday(&tend,NULL);  
    34.     timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec;  
    35.     cout<<" Total Time="<<timeUsed/1000<<" ms"<<endl;  
    36.     return 0;  
    37. }  


    Result:

    Sequential version:

    [cpp] view plain copy
     
    1. 0 Time=2064.69 ms  
    2. 1 Time=2061.11 ms  
    3. 2 Time=2076.32 ms  
    4. 3 Time=2077.93 ms  
    5.  Total Time=8280.14 ms  


    Parallel version:

    [cpp] view plain copy
     
    1. 2 Time=2148.22 ms  
    2. 3 Time=2151.72 ms  
    3. 0 Time=2151.85 ms  
    4. 1 Time=2151.77 ms  
    5.  Total Time=2158.81 ms  

    ------------------------------------------------------------------------------------------------------------------------------------------------------------

    Example2:矩阵拟合法计算Pi  

    Sequential Version:

    [cpp] view plain copy
     
    1. #include<iostream>  
    2. #include<sys/time.h>  
    3. #include<unistd.h>  
    4. //#include <omp.h>  
    5.   
    6. using namespace std;  
    7.   
    8. int main ()  
    9. {  
    10.     struct timeval tstart,tend;  
    11.     double timeUsed;  
    12.     static long num_steps =1000000000;  
    13.     double step;  
    14.     int i;  
    15.     double x, pi, sum = 0.0;  
    16.     step = 1.0/(double) num_steps;  
    17.     gettimeofday(&tstart,NULL);  
    18. //#pragma omp parallel for reduction(+:sum) private(x) /*只加了这一句,其他不变*/  
    19.     for (i=0;i < num_steps; i++)  
    20.     {  
    21.         x = (i+0.5)*step;  
    22.         sum = sum + 4.0/(1.0+x*x);  
    23.     }  
    24.     pi = step * sum;  
    25.     gettimeofday(&tend,NULL);  
    26.     timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec;  
    27.     timeUsed=timeUsed/1000;  
    28.     cout<<"pi="<<pi<<"  ("<<num_steps<<" )   "<<timeUsed<<" ms"<<endl;  
    29.     return 0;  
    30. }  

    Parallel Version:

    [cpp] view plain copy
     
    1. #include<iostream>  
    2. #include<sys/time.h>  
    3. #include<unistd.h>  
    4. #include <omp.h>  
    5.   
    6. using namespace std;  
    7.   
    8. int main ()  
    9. {  
    10.     struct timeval tstart,tend;  
    11.     double timeUsed;  
    12.     static long num_steps = 1000000000;  
    13.     double step;  
    14.     int i;  
    15.     double x, pi, sum = 0.0;  
    16.     step = 1.0/(double) num_steps;  
    17.     gettimeofday(&tstart,NULL);  
    18. #pragma omp parallel for reduction(+:sum) private(x) /*只加了这一句,其他不变*/  
    19.     for (i=0;i < num_steps; i++)  
    20.     {  
    21.         x = (i+0.5)*step;  
    22.         sum = sum + 4.0/(1.0+x*x);  
    23.     }  
    24.     pi = step * sum;  
    25.     gettimeofday(&tend,NULL);  
    26.     timeUsed=1000000*(tend.tv_sec-tstart.tv_sec)+tend.tv_usec-tstart.tv_usec;  
    27.     timeUsed=timeUsed/1000;  
    28.     cout<<"pi="<<pi<<"  ("<<num_steps<<" )   "<<timeUsed<<" ms"<<endl;  
    29.     return 0;  
    30. }  

    运行结果为:

    [cpp] view plain copy
     
    1. von@von-pc:~/test$ ./parrPI2  
    2. pi=3.14159  (1000000000 )   3729.68 ms  
    3. von@von-pc:~/test$ ./seqPI2  
    4. 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:http://www.cnblogs.com/yangyangcv/archive/2012/03/23/2413335.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&wumiiOpenMP编程指南)

    7:http://blog.163.com/zl_dream1106/blog/static/84286020105293213869/?suggestedreading&wumiiOpenMP 入门)

  • 相关阅读:
    原型与继承
    sqlserver优化管理
    vue 错误拦截
    axios 重新发起上次请求
    vue 滚动加载数据
    el-scrollbar组件
    ES服务器优化
    Aspose 生成pdf行距的不正确的问题,行距变高
    DocumentFormat.OpenXml.dll通過word做好的模板生成word
    stm32f103 rt-thread fal easyflash移植过程
  • 原文地址:https://www.cnblogs.com/mfryf/p/6863089.html
Copyright © 2011-2022 走看看