性能优化-OpenMP基础教程(二)

本文主要介绍OpenMP并行编程技术,编程模型、指令和函数的介绍、以及OpenMP实战的几个例子。希望给OpenMP并行编程者提供指导。

🎬个人简介:一个全栈工程师的升级之路!
📋个人专栏:高性能(HPC)开发基础教程
🎀CSDN主页 发狂的小花
🌄人生秘诀:学习的本质就是极致重复!

目录

一、OpenMP 简介

二、OpenMP 编程模型

1. 指令与库函数

1.1 OpenMP指令格式

1.1.1 并行区域(Parallel Region)

1.1.2 并行构造(Parallel Construct)

1.1.3 任务(Task)

1.1.4 同步(Synchronize)

1.2 OpenMP常用的指令和函数

1.3 OpenMP常用库函数

2. 并行执行

3. 线程管理

4. 同步与通信

5. 调度策略

三、OpenMP编程实战

1 Linux下编译选项

2 C语言 OpenMP 并行化程序示例(包含)

3 C++ OpenMP并行编程示例(包含宏定义#ifdef _OPENMP)

4 OpenMP 多线程性能对比


一、OpenMP 简介

        OpenMP 是一个为共享内存并行计算设计的编程接口,广泛应用于 Fortran、C 和 C++ 语言。它提供了一套编译器指令和库函数,使得开发者能够轻松地编写并行程序。OpenMP 的“fork/join”模型是其中最核心的并行执行模式,其中最初只有一个主线程在运行。当遇到需要并行计算的部分时,主线程会派生出其他线程来执行并行任务。当并行代码执行完毕,派生的线程会退出或挂起,控制权回到主线程。类似与多线程技术。

二、OpenMP 编程模型

1. 指令与库函数

        OpenMP 的基本语法是通过预处理指令 #pragma omp 来实现的。例如,#pragma omp parallel for 用于并行化 for 循环。此外,OpenMP 还提供了一系列的库函数,用于线程的创建、同步等操作。这些库函数和指令使得开发者能够更灵活地控制并行程序的执行。

1.1 OpenMP指令格式

1.1.1 并行区域(Parallel Region)

        用于指定一个代码块,该代码块将在多个线程上并行执行。

#pragma omp parallel
{// 并行执行的代码块
}
1.1.2 并行构造(Parallel Construct)

        用于创建一个新线程并执行指定的代码块

#pragma omp parallel sections
{#pragma omp section{// 线程1执行的代码块}#pragma omp section{// 线程2执行的代码块}
}
1.1.3 任务(Task)

        用于创建一个新任务并在当前线程上执行指定的代码块。

#pragma omp task firstprivate(a, b) shared(c)
{// 任务执行的代码块,使用变量a和b,以及共享变量c
}
1.1.4 同步(Synchronize)

        用于等待所有线程完成指定的任务。

#pragma omp for schedule(static, chunk_size) reduction(+:sum)
for (int i = 0; i < n; i++) {// 循环体,使用变量i和sum
}

1.2 OpenMP常用的指令和函数

  1. parallel:用于指定一个代码段,该代码段将在多个线程上并行执行。

  2. for:用于for循环之前,将循环分配到多个线程中并行执行,必须保证每次循环之间无相关性。

  3. parallel for:parallel 和 for语句的结合,也是用在一个for循环之前,表示for循环的代码将被多个线程并行执行。

  4. sections:用在可能会被并行执行的代码段之前。

  5. parallel sections:parallel和sections两个语句的结合。

  6. critical:用在一段代码临界区之前。

  7. single:用在一段只被单个线程执行的代码段之前,表示后面的代码段将被单线程执行。

  8. flush:用来保证线程的内存临时视图和实际内存保持一致,即各个线程看到的共享变量是一致的。

  9. barrier:用于并行区内代码的线程同步,所有线程执行到barrier时要停止,直到所有线程都执行到barrier时才继续往下执行。

  10. atomic:用于指定一块内存区域被制动更新。

  11. master:用于指定一段代码块由主线程执行。

  12. ordered:用于指定并行区域的循环按顺序执行。

  13. threadprivate:用于指定一个变量是线程私有的。

  14. copyprivate:配合single指令,将指定线程的专有变量广播到并行域内其他线程的同名变量中;

  15. copyin n:用来指定一个threadprivate类型的变量需要用主线程同名变量进行初始化;

  16. default:用来指定并行域内的变量的使用方式,缺省是shared。

1.3 OpenMP常用库函数

        OpenMP库函数是一组用于并行计算的函数,它们可以帮助程序员在C、C++和Fortran等编程语言中实现多线程编程。以下是一些常用的OpenMP库函数:

  1. omp_get_num_threads():返回正在执行的线程数。
  2. omp_get_max_threads():返回支持的最大线程数。
  3. omp_get_thread_num():返回当前线程的编号。
  4. omp_get_num_procs():返回正在执行的程序的处理器数。
  5. omp_set_num_threads():设置并行区域中的线程数。
  6. omp_get_nested():测试当前块是否嵌套在其他并行区域内。
  7. omp_set_nested():设置当前块允许嵌套在其他并行区域内。
  8. omp_get_schedule():获取指定并行区域的调度策略。
  9. omp_set_schedule():设置指定并行区域的调度策略。
  10. omp_get_chunk_size():获取指定并行区域的块大小。
  11. omp_set_chunk_size():设置指定并行区域的块大小。
  12. omp_barrier():在所有线程都到达该点时阻塞所有线程。
  13. omp_critical():创建一个临界区,确保同一时间只有一个线程可以执行该段代码。
  14. omp_atomic():对一个变量进行原子操作,确保多个线程对该变量的操作是有序的。
  15. omp_flush():将缓冲区中的数据立即写入共享内存或设备。
  16. omp_lock_t:用于同步的锁类型。
  17. omp_init_lock():初始化锁对象。
  18. omp_destroy_lock():销毁锁对象。
  19. omp_set_lock():对锁对象加锁。
  20. omp_unset_lock():对锁对象解锁。

2. 并行执行

        OpenMP 提供了多种并行执行的方法,如 parallel for、parallel sections 等。这些方法使得开发者能够将代码块分配给多个线程执行,从而实现更高效的计算。通过合理地划分代码块和选择合适的并行执行方法,开发者可以显著提高程序的性能。

3. 线程管理

        OpenMP 提供了一些指令和函数,如 num_threads、thread_bind 等,用于设置和控制并行区域中的线程数量和绑定策略。这些功能使得开发者能够更好地控制并行程序的执行流程,确保程序的正确性和稳定性。

4. 同步与通信

        为了确保并行执行的正确性,OpenMP 提供了一些同步机制,如 barrier、critical、atomic 等。这些机制确保了线程之间的正确协作和数据一致性。此外,还提供了一些数据传输函数,如 reduction,用于实现线程之间的数据共享和计算结果的汇总。这些同步和通信机制是并行程序中必不可少的部分,它们确保了程序的正确性和可靠性。

5. 调度策略

        OpenMP 支持多种调度策略,如静态调度、动态调度和运行时调度。这些调度策略允许开发者根据需要选择合适的调度策略来优化程序的性能。通过合理地选择调度策略,开发者可以更好地平衡线程的负载和利用系统资源,从而提高程序的执行效率。

三、OpenMP编程实战

1 Linux下编译选项

        Linux下GCC编译器仅仅编译选项增加-fopenmp即可完成对OpenMP的支持。

2 C语言 OpenMP 并行化程序示例(包含<omp.h>)

#include <omp.h>#include <stdio.h>int main() {#pragma omp parallel forfor (int i = 0; i < 10; i++) {printf("Thread %d: %d\n", omp_get_thread_num(), i);}return 0;}

这个程序使用了 #pragma omp parallel for 指令将 for 循环进行并行化。在循环体内部,使用 omp_get_thread_num() 函数获取当前线程的编号,并打印出来。这个示例展示了 OpenMP 的基本用法和并行化效果,通过简单的修改和调整,你可以将其应用于更复杂的并行计算任务。

        运行结果:

        由于使用的电脑是八核的,因此,最多有八个线程,由上述的线程编号可以看出。

如果将上述的循环代码变成8个,如下:

#include <omp.h>#include <stdio.h>int main() {#pragma omp parallel forfor (int i = 0; i < 8; i++) {printf("Thread %d: %d\n", omp_get_thread_num(), i);}return 0;}

        运行结果:

        运行结果是八个线程,线程编号和循环编号相同。

3 C++ OpenMP并行编程示例(包含宏定义#ifdef _OPENMP)

#include <iostream>
#include <omp.h>
int main()
{#ifdef _OPENMP // 如果定义了这个宏std::cout << "Hello, OpenMP!" << std::endl;#pragma omp parallel forfor (int i = 0;i < 8;i++){printf("thread ID is %d i = %d\n",omp_get_thread_num(),i);}#elsestd::cout << "OpenMP is not enabled." << std::endl;#endifreturn 0;
}

        运行结果:

        C++ OpenMP并行编程例子。-fopenmp编译选项开启后,_OPENMP宏被打开。

4 OpenMP 多线程性能对比

#include <stdlib.h>
#include <stdio.h>
#include "omp.h"void test()
{for (int i = 0; i < 80000; i++){//执行代码}
}int main(int argc, char **argv){#ifdef _OPENMPprintf("OpenMP is Enable!\n");#elseprintf("OpenMP is Disable!\n");#endiffloat startTime = omp_get_wtime();//指定2个Thread
#pragma omp parallel for num_threads(2)for (int i = 0; i < 80000; i++){test();}float endTime = omp_get_wtime();printf("2 个Thread,latency: %f\n", endTime - startTime);startTime = endTime;//指定4个Thread
#pragma omp parallel for num_threads(4)for (int i = 0; i < 80000; i++){test();}endTime = omp_get_wtime();printf("4 个Thread,latency: %f\n", endTime - startTime);startTime = endTime;//指定8个Thread
#pragma omp parallel for num_threads(8)for (int i = 0; i < 80000; i++){test();}endTime = omp_get_wtime();printf("8 个Thread,latency: %f\n", endTime - startTime);startTime = endTime;//指定12个Thread#pragma omp parallel for num_threads(10)for (int i = 0; i < 80000; i++){test();}endTime = omp_get_wtime();printf("10 个Thread,latency: %f\n", endTime - startTime);startTime = endTime;//不使用OpenMPfor (int i = 0; i < 80000; i++){test();}endTime = omp_get_wtime();printf("不使用OpenMP Mutil Thread,latency: %f\n", endTime - startTime);startTime = endTime;return 0;
}

        运行结果:

        分析结果可知,随着线程数量的增加运行的时间减少,由于使用的电脑是八核的,因此并行只能同时有八个线程,使用十个线程的运行效率不增反减。

🌈我的分享也就到此结束啦🌈
如果我的分享也能对你有帮助,那就太好了!
若有不足,还请大家多多指正,我们一起学习交流!
📢未来的富豪们:点赞👍→收藏⭐→关注🔍,如果能评论下就太惊喜了
感谢大家的观看和支持!最后,☺祝愿大家每天有钱赚!!!

下一节将继续开展OpenMP编程更加详细的实战。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/603473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习Redis缓存

学习Redis缓存 NoSQL和SQL的区别缓存缓存作用缓存成本添加Redis缓存 Redis特征Redis中数据结构Redis通用命令String类型Key的层级格式Hash类型Redis的Java客户端 NoSQL和SQL的区别 缓存 缓存就是数据交换的缓冲区&#xff0c;是存储数据的临时地方&#xff0c;一般读写性比较高…

async和await关键字

目录 async 关键字await 关键字使用 async 和 await 解决回调地狱问题错误处理总结 在JavaScript中&#xff0c; async和 await是用于简化基于 Promise的异步编程的关键字。在ES2017&#xff08;也称为ES8&#xff09;中引入后&#xff0c;它们迅速成为管理异步代码的首选方…

SQL高级:事务

在前面的内容中,我们学习了很多SQL的高级语法,包括窗口函数,存储过程等。在这篇文章中,我们要学习一个很重要的概念,事务。 事务的定义 为了讲清楚事务,很多人拿银行转账来举例,不得不说这真的是一个非常恰当的例子。一个账户要增加对应的金额,另一个账户需要减少对应…

RT-DETR Gradio 前端展示页面

效果展示 使用方法 Gradio 是一个开源库,旨在为机器学习模型提供快速且易于使用的网页界面。它允许开发者和研究人员轻松地为他们的模型创建交互式的演示,使得无论技术背景如何的人都可以方便地试用和理解这些模型。使用Gradio,你只需几行代码就可以生成一个网页应用程序,…

【C程序设计】C函数指针与回调函数

函数指针 函数指针是指向函数的指针变量。 通常我们说的指针变量是指向一个整型、字符型或数组等变量&#xff0c;而函数指针是指向函数。 函数指针可以像一般函数一样&#xff0c;用于调用函数、传递参数。 函数指针变量的声明&#xff1a; typedef int (*fun_ptr)(int,i…

mysql之视图mysql连接案例索引

文章目录 一、视图1.1 含义1.2 操作1.2.1 创建视图1.2.2 视图的修改1.2.3 删除视图1.2.4 查看视图 二、连接案例01)查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数02)查询同时存在" 01 "课程和" 02 "课程的情况03&#xff0…

【信息论与编码】习题-判断题-第二部分

目录 判断题 第二部分24. 信道矩阵 代表的信道的信道容量C125. 信源熵具有严格的下凸性。26. 率失真函数对允许的平均失真度具有上凸性。27. 信道编码定理是一个理想编码的存在性定理&#xff0c;即&#xff1a;信道无失真传递信息的条件是信息率小于信道容量 。28. 信道的输出…

修改 Ubuntu 的配置

目录 一、修改地址 1. 修改本机IP 二、修改网关 1. 查看网关地址 2. 设置默认网关 三、重启网络 1. 重启网络 2. 刷新网络 四、修改主机名 1. 查看主机名 2. 修改主机名 一、修改地址 1. 修改本机IP sudo ifconfig en…

【视频图像篇】模糊图像增强技术之视频平均帧处理

【视频图像篇】模糊图像增强技术之视频平均帧处理 0、目录 1、实验环境 2、集成和超级分辨率 3、色彩清晰化 4、翻转 总结 1、实验环境 系统环境Windows 11 专业版&#xff0c;[23H2&#xff08;22631.2715&#xff09;Impress&#xff0c;[v8.0.3.2] 2、集成和超级分辨…

如何使用VsCode编译C语言?

下载VsCode (1) 解压到D盘跟目录 (2) 运行[vscode.reg]&#xff0c;注册右键菜单 (3) 进入[pack]文件夹&#xff0c;运行[install.bat]。安装基本插件。 下载mingw32 (1) 解压任意目录 (2) 我的电脑右键–高级系统设置–高级–环境变量–系统变量–Path(双击)–空白行(双击)–…

MySQL之视图索引执行计划

目录 一.视图 二.执行计划 2.1.什么是执行计划 2.2.执行计划的作用 三.使用外连接、内连接和子查询进行举例 四.思维导图 好啦今天就到这里了哦&#xff01;&#xff01;&#xff01;希望能帮到你哦&#xff01;&#xff01;&#xff01; 一.视图 含义 &#xff1a;在数…

二手买卖、废品回收小程序 在app.json中声明permission scope.userLocation字段 教程说明

处理二手买卖、废品回收小程序 在app.json中声明permission scope.userLocation字段 教程说明 sitemapLocation 指明 sitemap.json 的位置&#xff1b;默认为 ‘sitemap.json’ 即在 app.json 同级目录下名字的 sitemap.json 文件 找到app.json这个文件 把这段代码加进去&…

@Transactional 注解的12种失效场景

请直接看原文: 原文链接:啪&#xff01;啪&#xff01;Transactional 注解的12种失效场景&#xff0c;这坑我踩个遍-腾讯云开发者社区-腾讯云 (tencent.com) ------------------------------------------------------------------------------------------------------------…

Kafka(四)Broker

目录 1 配置Broker1.1 Broker的配置broker.id0listererszookeeper.connectlog.dirslog.dir/tmp/kafka-logsnum.recovery.threads.per.data.dir1auto.create.topics.enabletrueauto.leader.rebalance.enabletrue, leader.imbalance.check.interval.seconds300, leader.imbalance…

在VM下使用Composer完成快照方式的软件制作

Composer允许您构建软件、应用程序、偏好设置文件或是文档的安装包&#xff0c;安装包可以部署到远程电脑或是作为镜像流程的一部分。构建软件包的第一步就是创建包源&#xff0c;根据要打包的软件&#xff0c;Composer允许您监视软件的安装和使用驱动器上已存在的文件来创建包…

旋转图像【矩阵】

Problem: 48. 旋转图像 文章目录 思路 & 解题方法复杂度Code 思路 & 解题方法 用深拷贝就行了。 复杂度 时间复杂度: 添加时间复杂度, 示例&#xff1a; O ( n ) O(n) O(n) 空间复杂度: 添加空间复杂度, 示例&#xff1a; O ( n ) O(n) O(n) Code class Solution:d…

Redis小计(4)

目录 1.Set和Get操作 2.mset和mget 3.mset&#xff0c;mget&#xff0c;set后加参数的优点 4.incr,incrby&#xff0c;incrbyfloat 1.Set和Get操作 flushall&#xff1a;清除所有k-v键值对。&#xff08;删库跑路小技巧&#xff09; set k v[ex | px]&#xff1a;设置超时…

利用python将excel文件转成txt文件,再将txt文件上传hdfs,最后传入hive中

将excel文件转成txt文件&#xff0c;再将txt文件上传hdfs&#xff0c;最后传入hive中 注意的点 &#xff08;1&#xff09;先判断写入的txt文件是否存在&#xff0c;如果不存在就需要创建路径 &#xff08;2&#xff09;如果txt文件已经存在&#xff0c;那么先将对应的文件进行…

高性能、可扩展、分布式对象存储系统MinIO的介绍、部署步骤以及代码示例

详细介绍 MinIO 是一款流行的开源对象存储系统&#xff0c;设计上兼容 Amazon S3 API&#xff0c;主要用于私有云和边缘计算场景。它提供了高性能、高可用性以及易于管理的对象存储服务。以下是 MinIO 的详细介绍及优缺点&#xff1a; 架构与特性&#xff1a; 开源与跨平台&am…