我刚刚开始研究OpenMP,并且已经开始阅读任务。看来Sun在这里的例子实际上比顺序版慢。我认为这与任务创建和管理的开销有关。它是否正确?如果是这样,有没有办法在不改变算法的情况下使用任务更快地编写代码?
int fib(int n)
{
int i, j;
if (n<2)
return n;
else
{
#pragma omp task shared(i) firstprivate(n)
i=fib(n-1);
#pragma omp task shared(j) firstprivate(n)
j=fib(n-2);
#pragma omp taskwait
return i+j;
}
}
答案 0 :(得分:5)
唯一合理的方法是将并行度降低到一定水平,低于这个水平就没有意义,因为开销变得比正在完成的工作更大。最好的方法是使用两个单独的fib
实现 - 一个串行一个,比如fib_ser
,一个并行的fib
- 并在给定的阈值下在它们之间切换
int fib_ser(int n)
{
if (n < 2)
return n;
else
return fib_ser(n-1) + fib_ser(n-2);
}
int fib(int n)
{
int i, j;
if (n <= 20)
return fib_ser(n);
else
{
#pragma omp task shared(i)
i = fib(n-1);
#pragma omp task shared(j)
j = fib(n-2);
#pragma omp taskwait
return i+j;
}
}
此处的阈值为n == 20
。它是任意选择的,其最佳值在不同的机器和不同的OpenMP运行时间上会有所不同。
另一种选择是使用if
子句动态控制任务:
int fib(int n)
{
int i, j;
if (n<2)
return n;
else
{
#pragma omp task shared(i) if(n > 20)
i=fib(n-1);
#pragma omp task shared(j) if(n > 20)
j=fib(n-2);
#pragma omp taskwait
return i+j;
}
}
如果n <= 20
,这将关闭两个显式任务,并且代码将以串行方式执行,但OpenMP代码转换仍然会有一些开销,因此它将比以前的版本运行速度慢单独的串行实现。
答案 1 :(得分:3)
你是对的,减速与任务创建和管理的开销有关。
添加if(n> 20)是修剪任务树的好方法,通过不创建第二个任务可以进行更多优化。当生成新任务时,父线程什么都不做。通过允许父任务处理其中一个fib调用而不是创建更多任务来加速代码:
int fib(int n){
int i, j;
if (n < 2)
return n;
else{
#pragma omp task shared(i) if(n > 20)
i=fib(n-1);
j=fib(n-2);
#pragma omp taskwait
return i+j;
}
}