当前位置: 首页 > news >正文

高性能计算之OpenMP——超算习堂学习2

OpenMP学习2——超算习堂

一、for指令的使用方法细嚼

1.1、parallel for指令的用法

在OpenMP并行程序设计中,for循环是一种独立的并行指令。它非常重要!它的指令格式是:

#include<omp.h>#pragmaomp parallelforfor(i=begin;i<end;++i){// Content}
十分需要注意的是:

parallel for指令的后面必须要紧跟for语句块!!!!

并且for循环并行必须要处在parallel并行区块内!!!!否则会当作串行执行!

1.2、parallel for指令的执行机制

此前一篇博客已经说明了,OpenMP的并行计算模式是插入并行语句的方法,如上图。当我们的串行程序执行到并行语句块的时候,会从主线程中派生出线程组,然后线程组对计算任务进行均分,然后并行计算。并行计算结束后重新回到串行程序。

1.3、parallel for并行程序设计案例

案例1:计算两个向量的点乘
#include<omp.h>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>constintmaxn=5e7;constintmod=10000;intvec1[maxn],vec2[maxn],vec[maxn],i;intmain(){srand((unsignedint)time(NULL));for(i=0;i<maxn;++i){vec1[i]=rand()%mod;vec2[i]=rand()%mod;}printf("--------------before parallel compute---------------\n");clock_t s,t;s=clock();for(i=0;i<maxn;++i){vec[i]=vec1[i]*vec2[i];}t=clock();printf("--------------used time = %d ms---------------\n",t-s);s=clock();printf("--------------enter parallel compute---------------\n");#pragmaomp parallelnum_threads(20)shared(vec1,vec2,vec)private(i){#pragmaompforfor(i=0;i<maxn;++i){vec[i]=vec1[i]*vec2[i];}}t=clock();printf("--------------used time = %d ms---------------\n",t-s);return0;}
计算效率对比:

案例2:parallel for并行计算矩阵乘法
#include<omp.h>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>constintmaxn=1000;constintmod=10000;intvec1[maxn][maxn],vec2[maxn][maxn],vec[maxn][maxn],i,j,k;intmain(){srand((unsignedint)time(NULL));for(i=0;i<maxn;++i){for(j=0;j<maxn;++j){vec1[i][j]=rand()%mod;vec2[i][j]=rand()%mod;}}printf("--------------before parallel compute---------------\n");clock_t s1,t1,s2,t2;s1=clock();for(i=0;i<maxn;++i){for(j=0;j<maxn;++j){for(k=0;k<maxn;++k){vec[i][j]+=(vec1[i][k]*vec2[k][j]);}}}t1=clock();printf("----------------used time = %d ms-----------------\n",t1-s1);printf("--------------enter parallel compute---------------\n");s2=clock();#pragmaomp parallelforcollapse(2)schedule(dynamic)private(i,j,k)shared(vec1,vec2,vec)for(i=0;i<maxn;++i){for(j=0;j<maxn;++j){for(k=0;k<maxn;++k){vec[i][j]+=(vec1[i][k]*vec2[k][j]);}}}t2=clock();printf("----------------used time = %d ms-----------------\n",t2-s2);printf("\n----------------the speedup ratio = %lf---------------\n",1.0*(t1-s1)/(t2-s2));return0;}
运行结果如下:

1.4、运用omp parallel for的一些注意事项

第一:omp parallel for 和 omp for 不要混用

一旦在前面有使用过

#pragmaomp parallel...

语句,并且当前还处在这个并行区,然后这个时候你想使用for循环并行,则千万不要再搞一次:

#pragmaomp parallelfor

这样的操作了,因为这样会让线程组重组,然后相当于有两重并行,举个例子看看:

在有#pragma omp parallel 的并行区下运行
#include<omp.h>#include<iostream>usingnamespacestd;intmain(){#pragmaomp parallelnum_threads(10){#pragmaompforfor(inti=0;i<5;++i){#pragmaomp critical{cout<<"i = "<<i<<endl;}}}return0;}

此时的运行结果是:

然后如果你多此一举多搞一遍parallel命令就会:
#include<omp.h>#include<iostream>usingnamespacestd;intmain(){#pragmaomp parallelnum_threads(4){#pragmaomp parallelfor// 注意看这里哦for(inti=0;i<5;++i){#pragmaomp critical{cout<<"i = "<<i<<endl;}}}return0;}

看看这样的“多此一举”的运行结果:

我们会发现,这个0 ~ 4 被重复执行啦!这样会影响并行程序结果,还会误以为运行的开销变大哦!!!!

造成这种结果的原因就是:parallel命令会告诉操作系统,此时我要重组线程组,要重新开始并行程序运行。然后这下好啦,每个线程到了那句指令的时候都重组线程组,白白多执行4次(取决于线程数)

二、多线程下数据访问同步

2.1、同步一词在并行计算的含义

其实同步啊,在并行计算里有两种含义:

第一:线程/进程的运行有的快有的慢,我想要在某处各个线程/进程达到同样的状态,这叫并行程序的运行同步

第二:对于共享内存的模型,我们需要控制数据的访问,达到线程同步。这样做的目的是为了防止多个进程/线程同时访问某个数据、内存,导致该数据同时改变,这样的作用下会让数据失真!举个例子:初始有变量a = 2,比如线程A要让a++,线程B要让a*=2。如果不控制访问,让变量a(或者某语句块)的执行的时候只能让一个线程进入执行,其他线程等待执行。则会让资源出现同步问题。这就叫数据同步。

2.2用critical创建临界区的方式避免线程同步危害

#include<omp.h>#include<iostream>usingnamespacestd;intmain(){inti,len,cnt=0;#pragmaomp parallelnum_threads(6){len=omp_get_num_threads();#pragmaompforprivate(i)for(i=0;i<len;++i){#pragmaomp critical{cout<<"Current is "<<i<<endl;cnt+=i;}}}cout<<"cnt = "<<cnt<<endl;return0;}
利用critical指令完成线程同步的运行结果:

http://www.jsqmd.com/news/1120994/

相关文章:

  • 如何高效使用智能技能管理工具:开发者的完全实战指南
  • HsMod终极指南:高效自定义你的炉石传说游戏体验
  • gprMax项目代码分解:理解 gprMax的项目结构、运行主线与开发模块
  • MZmine 3终极指南:如何免费快速处理质谱数据的完整解决方案
  • Slash实战案例:从代码示例到真实项目,教你如何优雅实现复杂富文本界面
  • EFCore 反向工程
  • 自定义View之文字测量原理与文字特效实现
  • AI 学习路径推荐:别把薄弱点变成焦虑清单
  • PoseDiffusion部署实战:从本地测试到生产环境的完整指南
  • DocStrap社区贡献指南:如何参与项目开发与问题修复
  • 线性回归最小二乘法 Python 3.12 实现:从公式推导到 15 行核心代码
  • 省时省力!德国宣誓翻译驾照认证件去哪办?24小时出件全攻略
  • cdc同步工具
  • AI大模型驱动自动化测试:从原理到落地的全链路实践指南
  • nginx模块以及反向代理配置
  • 【Java课程设计/毕业设计】基于 SpringBoot 的数字科技风险报告管理系统的设计与实现智能化科技风险报告编制与溯源管理系统【附源码、数据库、万字文档】
  • 5分钟掌握163MusicLyrics:让每首歌都有完美歌词的终极解决方案
  • 从0到1打造终端工作流:gh_mirrors/do/dotfiles-archive的插件与主题安装教程
  • JoyAI-Image-Edit-Plus参数优化指南:30步出图+CFG=4.0,效果提升300%的秘密
  • Tabled API集成指南:如何将表格提取功能嵌入到你的应用中
  • Micro Journal Rev.7电子墨水屏版本:护眼写作的革命性突破
  • 融云「北极星」数据监控平台:数据可视通晓全局,精准分析定位问题
  • Auto Playwright:用自然语言驱动AI自动化测试,提升测试效率与健壮性
  • Instatic媒体批量上传:拖放功能与进度监控的终极指南
  • Android Debug Bridge (ADB) v1.0.41
  • 协议之RTCP介绍
  • readpe高级用法:CSV/XML/HTML输出格式定制与自动化分析技巧
  • postcss-write-svg与构建工具集成:Gulp/Grunt/PostCSS配置教程
  • Windows Research Kernel (WRK) 本地过程调用(LPC):Windows进程间通信的内核实现
  • 陶瓷基板在PCB设计中的核心价值与应用解析