【问题标题】:Best way to parallelize this recursion using OpenMP使用 OpenMP 并行化此递归的最佳方法
【发布时间】:2016-12-04 17:25:13
【问题描述】:

我有以下递归函数(注意:它被剥夺了所有不重要的细节)

int recursion(...) {

  int minimum = INFINITY;
  for(int i=0; i<C; i++) {
      int foo = recursion(...);

      if (foo < minimum) {
          minimum = foo;
      }
  }

  return minimum;
}

注意2:它是有限,但在这个简化的例子中没有,所以请忽略它。这个问题的重点是如何正确地解决这个问题。

我在考虑使用tasks,但我不确定如何正确使用它——如何并行化内部循环。

编辑 1: 递归树不平衡。它与动态编程方法一起使用,因此随着时间的推移,许多值从以前的通道中重新使用。这让我很担心,我认为这将是一个很大的瓶颈。

C 大约是 20。

最好的指标是最快的:)

它将在 2x Xeon 上运行,因此有大量可用的硬件电源。

【问题讨论】:

  • 1) 您的工作负载/递归树的平衡程度如何? C 有多大 2) 你的“最佳”指标是什么? 3) 你设想它在什么规模的系统上运行?

标签: c++ c openmp


【解决方案1】:

是的,您可以使用 OpenMP 任务在多个递归级别上利用并行性,并确保不平衡不会导致循环浪费。

我会在vector 中收集结果并计算外面的最小值。您还可以在任务中执行受保护的(关键/锁定)最小计算。

如果递归太深,开销/工作比率变得太差,请避免生成任务/分配内存最少。最强大的解决方案是创建两个单独的(并行/串行)递归函数。这样一来,一旦切换到串行函数,运行时开销就为零 - 而不是每次在统一函数中都根据阈值检查递归深度。

int recursion(...) {
    #pragma omp parallel
    #pragma omp single
    return recursion_par(..., 0);
}

int recursion_ser(...) {
    int minimum = INFINITY;
    for(int i=0; i<C; i++) {
        int foo = recursion_ser(...);
        if (foo < minimum) {
            minimum = foo;
        }
    }
    return minimum;
}

int recursion_par(..., int depth) {
    std::vector<int> foos(C);
    for(int i=0; i<C; i++) {
        #pragma omp task
        {
            if (depth < threshhold) {
                foos[i] = recursion_par(..., depth + 1);
            } else {
                foos[i] = recursion_ser(...);
            }
        }
    }
    #pragma omp taskwait
    return *std::min_element(std::begin(foos), std::end(foos));
}

显然你不能在不重要的细节中对全局/共享状态做任何讨厌的事情。

【讨论】:

  • 你能解释一下recursion_omp(...);depth是什么吗??
  • @MaruthiAdithya 函数名是错字(应该是recursion_par)。我在代码中修复了这个问题,并添加了一个示例 depth 跟踪如何工作。
  • 谢谢您,先生。明白了
猜你喜欢
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多