性能优化-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_nestled():测试当前块是否嵌套在其他并行区域内。
  7. omp_set_nestled():设置当前块是否嵌套在其他并行区域内。
  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 for
    
    for (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 for
    
    for (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 for
    for (int i = 0;i < 8;i++)
    {
        printf("thread ID is %d i = %d\n",omp_get_thread_num(),i);
    }
    #else
    std::cout << "OpenMP is not enabled." << std::endl;
    #endif
    return 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 _OPENMP

    printf("OpenMP is Enable!\n");
    #else
     printf("OpenMP is Disable!\n");
    #endif

    float 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;
    //不使用OpenMP
    for (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编程更加详细的实战。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

每日一练:LeeCode-LCR 123. 图书整理 I (反转链表)(简)【栈、头插法(虚拟头结点)、双指针、递归】

本文是力扣LeeCode-LCR 123. 图书整理 I &#xff08;简&#xff09; 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 书店店员有一张链表形式的书单&#xff0c;每个节点代表一本书&#xff0c;节点中的值表示书的编号。为…

漏洞扫描工具scan4all(15000+PoC)

scan4all拥有15000PoC漏洞扫描&#xff0c;23种应用弱口令爆破&#xff0c;7000Web指纹&#xff0c;146种协议&#xff0c;90000规则Port扫描。集成 vscan、nuclei、ksubdomain、subfinder等&#xff0c;充分自动化进行扫描。是一款Fuzz、HW打点、BugBounty神器等工具。 项目地…

Python入门第09篇(conda虚拟环境)

前言 一开始默认安装了最新的Python3.12&#xff0c;搞的倒也顺手&#xff0c;看别人会有不兼容的问题&#xff0c;在我这开始没出现。不过坑总会踩到的&#xff0c;这不就出问题了。pip install一个包一直不行&#xff0c;问了下度娘&#xff0c;说由于这个包使用了一些新技术…

caj转换成pdf有哪些方法?

caj转换成pdf有哪些方法&#xff1f;PDF是一个被广泛支持的文件格式&#xff0c;这种格式基本上在所有的操作系统和设备上都是支持使用的&#xff0c;也能够将PDF文件打开和查看的&#xff0c;相比于caj文件&#xff0c;它就只能通过一下特定的软件或者是插件才能够将caj打开或…

TDD-LTE 寻呼流程

目录 1. 寻呼成功流程 1.1 空闲态寻呼 1.2 连接态寻呼 2. 寻呼失败流程 2.1 Paging消息不可达 2.2 RRC建立失败 2.3 eNodeB未上发Initial UE message或达到超时 1. 寻呼成功流程 1.1 空闲态寻呼 寻呼成功&#xff1a;MME发起寻呼&#xff08;S1 接口发送Paing 消息&…

【HarmonyOS开发】分布式应用的开发实践(元旦快乐)

元旦快乐&#xff0c;再见2023&#xff0c;加油2024&#xff0c;未来可期&#xff0c;愿新的一年带来健康、幸福和成功&#xff01;&#x1f4aa; &#x1f4aa;&#x1f4aa; 多种设备之间能够实现硬件互助、资源共享&#xff0c;依赖的关键技术包括分布式软总线、分布式设备虚…

如何调用FastGPT的API

fastGPT提供兼容OpenAI格式的接口&#xff0c;但是还是有一些地方需要注意 新建一个应用&#xff0c;可以正常测试通过后。【外部使用】【API访问】【新建一个KEY】 我们在调用FastGPT API的时候&#xff0c;需要传递一个chatId的参数&#xff0c;这个是标识同一个会话的参数…

SpringBoot+SSM项目实战 苍穹外卖(08) 用户下单支付订单 内网穿透cpolar软件 绕开微信支付实现

继续上一节的内容&#xff0c;本节导入地址簿功能代码&#xff0c;并实现用户下单和订单支付功能。 这里写目录标题 导入地址簿功能代码接口分析代码实现 用户下单接口分析代码实现 订单支付内网穿透——cpolar软件代码导入绕开微信支付实现 导入地址簿功能代码 地址簿&#x…

注册 Mongodb 官网个人账号

上文 Mongodb基础介绍与应用场景我们简单说了一下 Mongodb 的场景 那么 我们先在他的官网创建一个个人账号 我们先访问官网 https://www.mongodb.com/zh-cn 这里 我们需要注册一下 这里 我们按要求填写信息 然后 点击下面创建账户 然后 点击下面创建账户 然后 他会要求我们邮…

OSCHINA Gitee 联合呈现,《2023 中国开源开发者报告》正式发布,总结分非常帮,可以免费看的报告!

《2023 中国开源开发者报告》 详细地址&#xff1a; https://talk.gitee.com/report/china-open-source-2023-annual-report.pdf 不需要收费下载&#xff01;&#xff01; 其中大模型的部分总结的非常棒 gietee 也支持 AI 模型托管了 如何在 Gitee 上托管 AI 模型 https://…

嵌入式视频播放器(mplayer)

1.文件准备&#xff1a; MPlayer-1.0rc2.tar.bz2 libmad-0.15.1b.tar.gz 直接Git到本地 git clone https://gitee.com/zxz_FINE/mplayer_tarball.git 2.文件夹准备&#xff1a; src存放解压后的源码文件&#xff0c;target_Mplayer存放编译安装的目标文件 mkdir src targe…

Ethercat“APWR配置从站地址”报文分析(0x0010:0x0011)

基于IgH主站接了3个从站&#xff0c;分析报文。 APWR&#xff1a;Auto Increment Physical Write。 一条Ethercat报文中可以包含多个子报文&#xff0c;每个子报文的地址由ADPADO组成&#xff0c;ADP即16 bit High Addr&#xff0c;ADO即16 bit Low Addr。APWR模式下&#xff…

git rebase(变基)应用场景

文章目录 git rebase(变基)应用场景1.git rebase -i HEAD~3 git rebase(变基)应用场景 使得提交记录变得简洁 现在我们模拟我们有多次提交记录&#xff0c;本地仓库有三条提交 整合成一条提交记录 1.git rebase -i HEAD~3 提交记录合并 HEAD~3合并三条记录 执行之后 然后把…

Graceful Response 构建 Spring Boot 下优雅的响应处理

一、Graceful Response Graceful Response 是一个 Spring Boot 技术栈下的优雅响应处理器&#xff0c;提供一站式统一返回值封装、全局异常处理、自定义异常错误码等功能&#xff0c;使用Graceful Response进行web接口开发不仅可以节省大量的时间&#xff0c;还可以提高代码质…

MySQL 高级SQL语句与存储过程

MySQL 高级(进阶) SQL 语句 实验环境以下两表&#xff1a; use kgc; create table location (Region char(20),Store_Name char(20)); insert into location values(East,Boston); insert into location values(East,New York); insert into location values(West,Los Angele…

ORACLE Primavera P6, Unifier v23.12 系统分享

引言 根据上周的计划&#xff0c;我近日简单制作了一个基于ORACLE Primavera P6 EPPM 以及Unifier 最新版23.12的虚拟机演示环境&#xff0c;里面包括了p6 和 unifier的全套系统服务 此虚拟系统环境仅用于演示、培训和测试目的。如要在生产环境中使用此虚拟机&#xff0c;请您…

Git开发工具基本使用

文章目录 前言Git仓库基本概念基本环境安装清除原先配置生成秘钥配置Host添加公钥Github添加Gitee添加测试 本地仓库基本概览查看提交日志(log)版本回退添加文件至忽略列表分支分支冲突 远程仓库推送到远程仓库从远程仓库中抓取和拉取 在Idea中使用Git总结 前言 这里只是对Git…

仓储9代巷道灯接口文档-V2.0

标签注册 仓储9代巷道灯注册 磁体靠近条码所在区域附近&#xff0c;触发巷道灯注册到系统 注册成功&#xff1a;闪红灯变绿灯常亮&#xff0c;之后熄灭 查询巷道灯信息接口 接口地址&#xff1a;192.168.1.200/wms/associate/queryIndicates 请求类型&#xff1a;applicat…

【DevOps】搭建 项目管理软件 禅道

文章目录 1、简介2、环境要求3、搭建部署环境3.1. 安装Apache服务3.2. 安装PHP环境&#xff08;以php7.0为例 &#xff09;3.3. 安装MySQL服务 4、搭建禅道4.1、下载解压4.2、 配置4.2.1、 启动4.2.2、自启动4.2.3、确认是否开机启动 5、成功安装 1、简介 禅道是国产开源项目管…

堆排序(C语言版)

一.堆排序 堆排序即利用堆的思想来进行排序&#xff0c;总共分为两个步骤&#xff1a; 1. 建堆 升序&#xff1a;建大堆 降序&#xff1a;建小堆 2. 利用堆删除思想来进行排序 1.1.利用上下调整法实现堆排序 第一步&#xff1a;建堆 好了&#xff0c;每次建堆都要问自己…