OpenMP递归任务

OpenMP recursive tasks

本文关键字:任务 递归 OpenMP      更新时间:2023-10-16

考虑以下计算斐波那契数的程序。
它使用OpenMP任务来并行化。

#include <iostream> 
#include <omp.h>
using namespace std;
int fib(int n)
{
    if(n == 0 || n == 1)
        return n;
    int res, a, b;
    #pragma omp parallel
    {
        #pragma omp single 
        {
            #pragma omp task shared(a)
            a = fib(n-1);
            #pragma omp task shared(b)
            b = fib(n-2);
            #pragma omp taskwait
            res = a+b;
        } 
    }
    return res;
  }
int main()
{  
    cout << fib(40);    
}

我使用gcc 4.8.2版本和Fedora 20。
在编译上述程序时,使用g++ -fopenmp name_of_program.cpp -Wall然后运行它,我发现在查看htop时只有两个(有时是3个)线程在运行。我运行这个程序的机器有8个逻辑cpu。我的问题是,我需要做些什么来卸载工作到8个线程。我尝试导出OMP_NESTED=TRUE,但这会导致在运行时出现以下错误计划:
libgome:线程创建失败:资源暂时不可用
我的程序的重点不是有效地计算斐波那契数,而是在OpenMP中使用任务或类似的东西

使用OMP_NESTED=FALSE,一组线程被分配到顶级并行区域,并且在每个嵌套层上没有额外的线程,因此最多有两个线程将做有用的工作。

使用OMP_NESTED=TRUE,在每个级别分配一组线程。在您的系统上有8个逻辑cpu,因此团队规模可能为8。该团队包括一个来自该地区以外的线程,因此只启动了7个新线程。fib(n)的递归树大约有fib(n)个节点。(fib的一个很好的自引用属性!)因此,代码可能会创建7*fib(n)个线程,这会很快耗尽资源。

解决方法是在整个任务树周围使用单个并行区域。将omp parallelomp single逻辑移到main,在fib之外。这样单线程团队就可以处理整个任务树。

一般的要点是要区分潜在的平行和实际的平行。任务指令指定潜在的并行性,在执行过程中可能会使用,也可能不会使用。omp parallel(用于所有实际目的)指定实际并行度。通常您希望实际的并行度与可用的硬件相匹配,这样就不会使机器陷入瘫痪,但是潜在的并行度要大得多,这样运行时就可以平衡负载。