0
点赞
收藏
分享

微信扫一扫

共享内存编程:OpenMP

Soy丶sauce 2022-04-23 阅读 59

共享内存编程:OpenMP

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

语句说明

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。

举报

相关推荐

0 条评论