C++ C++;OpenMP斐波那契:1个线程的执行速度比4个线程快得多
我试图理解为什么OpenMP上1个线程的运行速度要比4个线程的运行速度快得多。下面的代码实际上基于一个类似的问题:但是当尝试实现其中一个建议的答案时,我没有得到预期的加速,这表明我做错了什么(不确定是什么)。当在4个线程上运行下面的程序时,是否比在1个线程上运行更快?在4核上运行时,我的速度降低了10倍(我应该得到适度的加速,而不是明显的降低)C++ C++;OpenMP斐波那契:1个线程的执行速度比4个线程快得多,c++,openmp,C++,Openmp,我试图理解为什么OpenMP上1个线程的运行速度要比4个线程的运行速度快得多。下面的代码实际上基于一个类似的问题:但是当尝试实现其中一个建议的答案时,我没有得到预期的加速,这表明我做错了什么(不确定是什么)。当在4个线程上运行下面的程序时,是否比在1个线程上运行更快?在4核上运行时,我的速度降低了10倍(我应该得到适度的加速,而不是明显的降低) intfib(intn) { 如果(n==0 | | n==1) 返回n; if(n
intfib(intn)
{
如果(n==0 | | n==1)
返回n;
if(n<20)//编辑代码以包括截止
返回fib(n-1)+fib(n-2);
国际关系,a,b;
#pragma omp任务共享(a)
a=fib(n-1);
#pragma omp任务共享(b)
b=fib(n-2);
#pragma omp taskwait
res=a+b;
返回res;
}
int main(){
omp_集合_嵌套(1);
omp_设置_数量_线程(4);
双启动时间=omp\U get\U wtime();
#pragma-omp并行
{
#布拉格omp单曲
{
你试过很多次了吗
在多线程中,初始化CPU内核上的工作需要一些时间。对于在单个内核上完成速度非常快的较小作业,线程会因此降低作业的速度
如果作业通常花费的时间超过秒,而不是毫秒,则多线程显示速度提高
线程还存在另一个瓶颈。如果您的代码试图创建太多的线程(主要是通过递归方法),这可能会导致所有正在运行的线程延迟,从而导致大量的延迟
在这个wiki页面中,我们提到了这个函数,并建议手动关闭它。这个函数需要有两个版本,当线程太深时,它会继续使用单线程进行递归
编辑:在进入OMP区域之前,需要增加截止变量
以下代码用于OP测试的测试目的
#define CUTOFF 5
int fib_s(int n)
{
if (n == 0 || n == 1)
return n;
int res, a, b;
a = fib_s(n - 1);
b = fib_s(n - 2);
res = a + b;
return res;
}
int fib_m(int n,int co)
{
if (co >= CUTOFF) return fib_s(n);
if (n == 0 || n == 1)
return n;
int res, a, b;
co++;
#pragma omp task shared(a)
a = fib_m(n - 1,co);
#pragma omp task shared(b)
b = fib_m(n - 2,co);
#pragma omp taskwait
res = a + b;
return res;
}
int main()
{
omp_set_nested(1);
omp_set_num_threads(4);
double start_time = omp_get_wtime();
#pragma omp parallel
{
#pragma omp single
{
cout << fib_m(25,1) << endl;
}
}
double time = omp_get_wtime() - start_time;
std::cout << "Time(ms): " << time * 1000 << std::endl;
return 0;
}
我相信我不知道如何告诉编译器在一定深度后不要创建并行任务,因为:omp_set_max_active_levels似乎没有效果,omp_set_nested被弃用(尽管它也没有效果)
因此,我必须手动指定在哪个级别之后不创建更多任务。哪个IMHO令人伤心。我仍然相信应该有办法做到这一点(如果有人知道,请告诉我)。下面是我如何尝试的,输入大小为20的并行版本比串行版本运行快一点(比如70-80%的时间)。
参考:代码取自课程作业(未提供解决方案,因此我不知道如何有效地完成):
#包括
#包括
#包括
内部纤维(内部n,内部rec_高度)
{
int x=1,y=1;
if(n<2)
返回n;
int t计数=0;
if(rec_height>0)//令人惊讶的是,如果没有这个检查,并行代码比串行代码慢(我相信不需要它,我只是不知道如何使用OpneMP)
{
rec_高度-=1;
#pragma omp任务共享(x)
x=fib(n-1,记录高度);
#pragma omp任务共享(y)
y=fib(n-2,记录高度);
#pragma omp taskwait
}
否则{
x=fib(n-1,记录高度);
y=fib(n-2,记录高度);
}
返回x+y;
}
int main()
{
int tot_螺纹=16;
int recDepth=(int)log2f(tot_线程);
如果((int)pow(2,recDepth))
即使是大数字(>35),fibonacci在一个线程上比在多个线程上快得多。@user308485,甚至35都不是你想象的那么大的数字。我已经测试了这个嵌套方法,时间似乎与40后有关。在这个域中再试一次。使用更多的内核仍然没有任何好处。你刚刚测试过这段代码吗?你能在som中使用更多的内核获得一些加速吗e特定大小?看看fib()
子例程。它执行一次加法(例如计算)并“生成”两个线程(例如开销),因此,在这里使用OpenMP
毫无益处也就不足为奇了(一个for
循环甚至比递归实现更快)@user308485,我有一个编辑来解决你的问题,但是保留了前面的部分以备将来可能引用,你需要为你的函数添加一个截止点。别忘了,你需要两个版本的函数。哦,顺便说一下,你的代码不做并行循环,而是生成一个线程树,这就是为什么它需要太多时间的原因。fi中的每个数字bonacci序列取决于前面的数字。为什么这会有助于多线程处理?您不能期望任何性能提升。可以做的一件事是缓存已计算的fibonacci值。这会给您带来显著的加速。为什么omp\u set\u嵌套(1)
?我没有看到任何嵌套的并行部分。请提供1)具体的性能结果2)有关系统的信息3)a 4)编译器、版本和命令我在2x12 core Haswell E5/GCC上做了一些实验,加速比强烈依赖于截止参数。对于截止20,我的加速比大约为5,对于截止42,加速比大约为10对于24个线程。我计算了fib(48)
,较低的输入太快,无法得到相关的结果。
#define CUTOFF 5
int fib_s(int n)
{
if (n == 0 || n == 1)
return n;
int res, a, b;
a = fib_s(n - 1);
b = fib_s(n - 2);
res = a + b;
return res;
}
int fib_m(int n,int co)
{
if (co >= CUTOFF) return fib_s(n);
if (n == 0 || n == 1)
return n;
int res, a, b;
co++;
#pragma omp task shared(a)
a = fib_m(n - 1,co);
#pragma omp task shared(b)
b = fib_m(n - 2,co);
#pragma omp taskwait
res = a + b;
return res;
}
int main()
{
omp_set_nested(1);
omp_set_num_threads(4);
double start_time = omp_get_wtime();
#pragma omp parallel
{
#pragma omp single
{
cout << fib_m(25,1) << endl;
}
}
double time = omp_get_wtime() - start_time;
std::cout << "Time(ms): " << time * 1000 << std::endl;
return 0;
}
co=1 14.5s
co=2 9.5s
co=3 6.4s
co=10 7.5s
co=15 7.0s
co=20 8.5s
co=21 >18.0s
co=22 >40.0s
#include <stdio.h>
#include <omp.h>
#include <math.h>
int fib(int n, int rec_height)
{
int x = 1, y = 1;
if (n < 2)
return n;
int tCount = 0;
if (rec_height > 0) //Surprisingly without this check parallel code is slower than serial one (I believe it is not needed, I just don't know how to use OpneMP)
{
rec_height -= 1;
#pragma omp task shared(x)
x = fib(n - 1, rec_height);
#pragma omp task shared(y)
y = fib(n - 2, rec_height);
#pragma omp taskwait
}
else{
x = fib(n - 1, rec_height);
y = fib(n - 2, rec_height);
}
return x+y;
}
int main()
{
int tot_thread = 16;
int recDepth = (int)log2f(tot_thread);
if( ((int)pow(2, recDepth)) < tot_thread) recDepth += 1;
printf("\nrecDepth: %d\n",recDepth);
omp_set_max_active_levels(recDepth);
omp_set_nested(recDepth-1);
int n,fibonacci;
double starttime;
printf("\nPlease insert n, to calculate fib(n): %d\n",n);
scanf("%d",&n);
omp_set_num_threads(tot_thread);
starttime=omp_get_wtime();
#pragma omp parallel
{
#pragma omp single
{
fibonacci=fib(n, recDepth);
}
}
printf("\n\nfib(%d)=%d \n",n,fibonacci);
printf("calculation took %lf sec\n",omp_get_wtime()-starttime);
return 0;
}