试图通过OpenMP并行化递归函数的冗余计算

时间:2019-04-26 02:18:58

标签: c++ parallel-processing openmp cilk-plus

我有一个调用两次的递归函数。我试图对该函数进行并行化的尝试最终成功了,但是在此期间却进行了大量的冗余计算,从而抹去了并行性带来的所有收益。

主程序正在尝试计算辅助图,这是计算图的所有k边连接的组件所需的中间数据结构。

几个月来我一直在解决这个问题,我只决定在这里寻求帮助,作为不得已的选择。我将不胜感激任何指向正确方向的评论或建议;我并不一定要在盘子上寻找解决方案。

我尝试使用#pragma omp单次nowait,但这只会导致顺序执行代码。

我又一次尝试使用cilk_spawn,但这只会导致我的计算机内存不足。我想产生了太多的过程。

我将问题的实质提取到下面粘贴的最小工作示例中。

下面发布的代码将每次计算重复大约八次。我猜有八个不同的进程运行该程序的单独副本,而不是同时处理部分问题。

#include <iostream>
#include <omp.h>
#include <numeric>
#include <vector>
#include <random>
#include <algorithm>
using namespace std;

int foo(std::vector<int> V, int s){
    int n = V.size();

    if (n>1){
    std::cout<<n<<" ";
    std::random_device rd; // obtain a random number from hardware
    std::mt19937 eng(rd()); // seed the generator
    std::uniform_int_distribution<int> distr(0, n-1); // define the range
    int t = 1;

    auto first = V.begin();
    auto mid = V.begin() + (t);
    auto mid_1 = V.begin() + (t);

    std::vector<int> S(first, mid);
    std::vector<int> T(mid_1, V.end());

    #pragma omp parallel
    {
    #pragma omp task
    foo(S, s);
    #pragma omp task
    foo(T, t); 
    }
    }
   return 0;
}



int main(){
    std::vector<int> N(100);
    iota(N.begin(), N.end(), 0);
    int p = foo(N,0);
    return (0);
}

我的目标是使所有进程/线程一起工作以完成递归。

1 个答案:

答案 0 :(得分:0)

在您的示例中,将任务并行性与OpenMP结合使用的正确方法如下。

int foo(std::vector<int> V, int s)
{
    int n = V.size();

    if (n > 1)
    {
        std::cout << n << " ";
        std::random_device rd;                              // obtain a random number from hardware
        std::mt19937 eng(rd());                             // seed the generator
        std::uniform_int_distribution<int> distr(0, n - 1); // define the range
        int t = 1;

        auto first = V.begin();
        auto mid = V.begin() + (t);
        auto mid_1 = V.begin() + (t);

        std::vector<int> S(first, mid);
        std::vector<int> T(mid_1, V.end());

        #pragma omp task
        foo(S, s);
        #pragma omp task
        foo(T, t);
    }
    return 0;
}

int main()
{
    std::vector<int> N(10000);
    std::iota(N.begin(), N.end(), 0);
    #pragma omp parallel
    #pragma omp single
    {
        int p = foo(N, 0);
    }
    return (0);
}

也就是说,该特定示例不会显示性能改进,因为它本身非常快并且受内存分配支配。因此,如果您觉得应用此方法没有好处,请随时使用更具体的示例更新或发布新问题。