共享内存编程: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 陕西

相关推荐

部门氛围好,不卷,欢迎投递!
投递蚂蚁集团等公司10个岗位 >
点赞 评论 收藏
转发
1 2 评论
分享
牛客网
牛客企业服务