共享内存编程:OpenMP

共享内存编程:OpenMP(一)

  最近在上并行程序设计,我们知道在顺序不影响结果的for循环结构前可以使用OpenMP中的:
#pragma omp parallel [clause ...] if(scalar_expression) num_threads[integer] 来使用多线程进行加速

语句说明

pramga: 编译程序指令
omp: 用omp这个库来编译程序,需包含头文件omp.h,也可以选择其他库。
parallel for: 针对for的平行方式。
if(scalar_expression): 如果scalar_expression为true,则创建多线程进行并行,若scalar_expression为false,则不创建多线程,即忽略这条语句进行顺序运算。
num_threads[integer]: 指定integer个线程数。

并行原理概况

先介绍一下模型
Fork-Join model: 主线程指定数个次线程,给次线程分配任务,任务完成后返回主线程。上面的pramga就是用来分配线程、回收线程与分配任务的。

 多线程创建示意图
概况:
 1. 程序遇见#pragma,开始创建多线程。
 2. structure_block中的代码在各线程中被复制并执行。
 3. 在平行线程的尾部有一个抽象的屏障。
 4. 一个线程异常终止,所有线程终止。

限制

 - 并行区域一定要是一个单独的代码块,不要跨越其他代码区域与文件,否则会发生栈溢出等异常情况。
 - 在并行区域中不能使用分支语句,但是能调用其他function,但不太建议。

线程数

线程数受以下条件顺序影响:

 1. 如果if里面条件表达式为false,则顺序执行,即单线程;如果为true,则进行第2条判断。
E.g.:#pragma omp parallel IF(para == true)
 2. 通过clause:num_thread设定线程数
E.g.:#pragma omp parallel num_thread(10)

这里注意,线程数可以随意设定,但最多达到计算机所能运行的最大线程数,我们可以通过以下代码查看自己电脑的最大线程数:
#include<iostream>
#include<thread>
int main(){
    unsigned numThreads = std::thread::hardware_concurrency();
    std::cout << numThreads << std::endl;
    return 0;
}
  •  使用库函数omp_set_num_thread()设定线程,需要在需要平行计算的代码块之前调用。
  •  设置环境变量OMP_NUM_THREADS
  •  默认,通常设置为一个节点上GUP的数量。

嵌套并行

#pragma omp parallel num_thread(2)
{
	#pragma omp parallel num_thread(3)
	{
		cout << "hello parallel";
	}
}
共会输出6个“hello parallel”。
操作函数:
 - omp_get_nested(): 检测嵌套并行是否可行。
 - omp_set_nested(bool): 设置能否嵌套与OMP_NESTED环境变量。
 
 如果不能嵌套并行,就只能创建一个并行线程。 


例子

 来看一个矩阵相乘的例子:
void original(double *A, double *B, double *C, int m, int k, int n)
{
    for (int mi = 0; mi < m; mi++)
    {
        for (int ni = 0; ni < n; ni++)
        {
            for (int ki = 0; ki < k; ki++)
                C[mi * n + ni] += A[mi * k + ki] * B[ki * n + ni];
        }
    }
}
void parallel(double *A, double *B, double *C, int m, int k, int n)
{
    //here I insert 
    #pragma omp parallel for 
    for(int i = 0 ; i < m ; ++i){
        for(int ki = 0 ; ki < k ; ++ki){
            for(int j = 0 ; j < n ; ++j){
                C[i*n+j] += A[i*k+ki] * B[ki*n + j];
            }
        }
    }
}
进行1000 乘 1000,1000 乘 1000 的两个矩阵相乘,两者所用时间分别为:
在这里插入图片描述
2.99517s 
0.61946s

其他

应使用尽量少的#pramga for,因为它也需要时间开销。当有嵌套循环时,一般都在外层循环前加#prama for,如果外层循环数远小于内层循环数,可以在内层循环加#prama for。

全部评论
共享内存这个什么时候都需要啊
点赞 回复 分享
发布于 2022-08-17 19:10 陕西

相关推荐

03-15 14:55
已编辑
门头沟学院 golang
bg:双非学院本&nbsp;ACM银&nbsp;go选手timeline:3.1号开始暑期投递3.7号第二家公司离职顽岩科技&nbsp;ai服务中台方向&nbsp;笔试➕两轮面试,二面挂(钱真的好多😭)厦门纳克希科技&nbsp;搞AI的,一面OC猎豹移动&nbsp;搞AIGC方向&nbsp;一面OC北京七牛云&nbsp;搞AI接口方向&nbsp;一面OC上海古德猫宁&nbsp;搞AIGC方向&nbsp;二面OC上海简文&nbsp;面试撞了直接拒深圳图灵&nbsp;搞AIGC方向一面后无消息懒得问了,面试官当场反馈不错其他小厂没记,通过率80%,小厂杀手😂北京字节&nbsp;具体业务不方便透露也是AIGC后端方向2.28约面&nbsp;(不知道怎么捞的我,我也没在别的地方投过字节简历哇)3.6一面&nbsp;一小时&nbsp;半小时拷打简历(主要是AIGC部分)剩余半小时两个看代码猜结果(经典go问题)➕合并二叉树(秒a,但是造case造了10分钟哈哈)一天后约二面3.12&nbsp;二面,让我挑简历上两个亮点说,主要说的docker容器生命周期管理和raft协议使用二分法优化新任leader上任后与follower同步时间。跟面试官有共鸣,面试官还问我docker底层cpu隔离原理和是否知道虚拟显存。之后一道easy算法,(o1空间解决&nbsp;给定字符串含有{和}是否合法)秒a,之后进阶版如何用10台机加快构建,想五分钟后a出来。面试官以为45分钟面试时间,留了18分钟让我跟他随便聊,后面考了linux&nbsp;top和free的部分数据说什么意思(专业对口了只能说,但是当时没答很好)。因为当时手里有7牛云offer,跟面试官说能否快点面试,马上另外一家时间到了。10分钟后约hr面3.13,上午hr面,下午走完流程offer到手3.14腾讯技术运营约面,想直接拒😂感受:&nbsp;因为有AIGC经验所以特别受AI初创公司青睐,AIGC后端感觉竞争很小(指今年),全是简历拷打,基本没有人问我八股(八股吟唱被打断.jpeg),学的东西比较广的同时也能纵向深挖学习,也运气比较好了哈哈可能出于性格原因,没有走主流Java路线,也没有去主动跟着课写项目,项目都是自己研究和写的哈哈
烤点老白薯:你根本不是典型学院本的那种人,贵了你这能力
查看7道真题和解析
点赞 评论 收藏
分享
评论
1
2
分享

创作者周榜

更多
牛客网
牛客企业服务