【问题标题】:Parallelizing base case calculations for recursion using OpenMP使用 OpenMP 并行化递归的基本情况计算
【发布时间】:2011-02-21 10:09:56
【问题描述】:

我正在尝试学习 OpenMP 的概念,但偶然发现了一个案例,我很难掌握如何使用这个库来解决这个问题。

假设我们有以下递归函数

// ...
void recurse(int tmp[], int p, const int size)
{
   if (p == size)
   {
      // Computationally heavy, should be executed in its own "thread"
      performTask(tmp); // Note: Only requires read access
   }
   else
   {
      for(int i = 0; i < size; i++)
      {
         // Alter tmp and continue recursion
         tmp[p] = i;
         recurse(tmp, p+1, size);
      }
   }
}
// ...
int main(int argc, char * argv[])
{
    int tmp[10];
    recurse(tmp, 0, 10);
    return 0;
}

如何在使用 OpenMP 在主线程中生成新结构的同时并行执行 performTask

我知道有一种叫做“任务”的东西,我认为这就是我应该在这里使用的东西,但是我想出的所有东西根本没有任何性能提升。请指出正确的方向。

编辑:为了更好地解释,我将示例程序更具体。

【问题讨论】:

  • 您必须提供更多信息。 appendStuffOn 在做什么?如果它正在访问一个公共结构,那么您可能无法获得性能,因为该结构可能必须被锁定,并且在结构上锁定和解锁的开销以及通过该子程序基本上序列化代码可能会使性能更差比串行运行。
  • 使用single,也许?
  • appendStuffOn 将返回一个新的 tmp 副本。
  • 主要是递归函数是唯一改变结构的函数,performTask只是读取它。
  • 我的意思是作为评论 - 不是答案。下一个问题是什么时候 isDone 是真的?如果您在调用 performTask 之前执行所有 appendStuffOn 调用,那么并行化将无济于事。

标签: c recursion openmp


【解决方案1】:

下面的代码不能按原样工作,但希望它能为您指明正确的方向:

// ...
void recurse(int tmp[], int p, const int size)
{
   if (p == size)
   {
      // Computationally heavy, should be executed in its own "thread"
      // perform task using the thread pool
#pragma omp task     
      performTask(tmp); // Note: Only requires read access
   }
   else
   {
      for(int i = 0; i < size; i++)
      {
         // Alter tmp and continue recursion
         tmp[p] = i;
         recurse(tmp, p+1, size);
      }
   }
}
// ...
int main(int argc, char * argv[])
{    
    int tmp[10];
    // start threads
#pragma omp parallel
{
    // use single thread to construct `tmp` values
#pragma omp single nowait
    recurse(tmp, 0, 10);
}
    return 0;
}

代码基于Comparing Nested Parallel Regions and Tasking in OpenMP 3.0

【讨论】:

  • 您的一般结构是正确的。但是,它不起作用,因为 tmp 是一个指针,而不是数组本身。当 p == size 时,您需要复制数组以传递给函数 performTask。它可以是在块中声明的本地数组,但是在调用 performTask 之后您将需要一个 taskwait 以确保它在任务执行之前不会超出范围。
  • @ejd: int 数组只是一个占位符。第一个 OP 的编辑使用StructBeingBuiltOn。该结构正在由多个线程读取/写入,performTask() 期望tmp 是只读的,因此需要复制。 omp task firstprivate(copiable) 可以用来代替 taskwait,因为 performTask() 只需要读取权限。
  • @sebastian: firstprivate 不起作用,因为它会复制指针而不是数组
  • @ejd:请注意,我故意使用了copiable 而不是tmp。它代表具有值语义的对象,例如 structvector(与数组的引用语义相反)。
  • 我在评论上面的代码 - 正如发布的那样,它不能正常工作。您的可执行示例更好,但仍然不正确。您还应该将 size firstprivate 设置为任务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多