我试图理解为什么以下在1个线程上的运行速度比在OpenMP上的4个线程上运行得快得多。下面的代码实际上是基于一个类似的问题:OpenMP recursive tasks但是当我尝试实现其中一个建议的答案时,我没有达到预期的加速,这表明我做错了(并且不确定它是什么)。当在4个线程上运行下面而不是在1个线程上时,人们是否获得更好的速度?在4核上运行时,我的速度减慢了10倍(我应该获得适度的加速而不是显着的减速)。
int fib(int n)
{
if(n == 0 || n == 1)
return n;
if (n < 20) //EDITED CODE TO INCLUDE CUTOFF
return fib(n-1)+fib(n-2);
int res, a, b;
#pragma omp task shared(a)
a = fib(n-1);
#pragma omp task shared(b)
b = fib(n-2);
#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(25) << endl;
}
}
double time = omp_get_wtime() - start_time;
std::cout << "Time(ms): " << time*1000 << std::endl;
return 0;
}
答案 0 :(得分:2)
您是否尝试了大量的数据?
在多线程中,初始化CPU核心的工作需要一些时间。对于在单个核心上执行速度非常快的小型作业,线程会因此而减慢作业。
如果作业通常需要的时间超过秒,而不是毫秒,则多线程会显示速度增加。
线程还有另一个瓶颈。如果您的代码尝试创建太多线程(主要是通过递归方法),这可能会导致所有正在运行的线程延迟,导致大量回调。
在这个OpenMP/Tasks维基页面中,提到了它并建议手动切断。需要有2个版本的函数,当线程太深时,它会继续使用单线程进行递归。
编辑:在进入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;
}
结果: 当CUTOFF值设置为10时,计算第45个项的时间不到8秒。
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
答案 1 :(得分:0)
我相信我不知道如何告诉编译器在一定深度后不要创建并行任务,因为:omp_set_max_active_levels似乎没有任何作用,并且omp_set_nested已弃用(尽管它也没有作用)。
因此,我必须手动指定在哪个级别之后不创建更多任务。哪个恕我直言是可悲的。我仍然相信应该有一种方法(如果有人知道,请告诉我)。这是我尝试的方法,在输入大小为20的并行版本运行之后,运行速度比串行运行的快一些(例如70-80%的时间)。 参考:从课程分配中获取的代码(未提供解决方案,所以我不知道如何高效地执行):https://www.cs.iastate.edu/courses/2018/fall/com-s-527x
#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;
}