我有以下代码,我尝试使用OpenMP进行并行化。
int ncip(int dim, double R){
int n, r = (int)floor(R);
if (dim == 1) return 1 + 2*r;
#pragma omp task shared(n, dim)
n = ncip(dim-1, R); // last coord 0
for(int i=1; i<=r; ++i){
#pragma omp task shared(n, dim)
n += 2*ncip(dim-1, sqrt(R*R - i*i) ); // last coord +- i
}
return n;
}
我需要应用基于任务的并行性,因为递归调用但我没有在计算中显示任何加速。我究竟做错了什么 ?有什么建议可以帮助加快计算速度吗?
答案 0 :(得分:0)
并行性不是免费的,因此,无论如何,一个简单的pragma看起来像是,例如#pragma omp task
,它需要付出很大的代价,因为它隐藏了创建和同步线程,分配和排队任务等的整个逻辑。只有当你在计算强度,多线程本身的费用之间找到平衡时,和问题的大小,(更不用说多线程的副作用,如错误共享等),你会观察到正(> 1)加速。
另外,请记住,线程数总是有限的。一旦你已经为每个线程创建了足够的工作负载,不要试图通过添加额外的工作共享结构来增强代码 - 一个线程不能神奇地划分为两个单独的指令流。也就是说,如果你有一个已经并行的最顶层循环,并且它有足够的迭代来保持所有可用线程忙,那么你将无法获得任何试图提取嵌套并行性的东西。
话虽如此,除非你可以利用其他一些技术,比如记忆部分结果,或者完全删除递归,然后只使用一个最顶层的并行循环和一个reduction子句来确保对共享变量的线程安全访问:
#pragma omp parallel for reduction(+:n)
for (int i = 1; i <= r; ++i)
{
n = n + (2 * ncip(dim-1, sqrt(R*R - i*i)));
}
然后是一个简单的顺序函数:
int ncip(int dim, double R)
{
int n, r = (int)floor(R);
if (dim == 1)
{
return 1 + 2*r;
}
n = ncip(dim-1, R);
for (int i = 1; i <= r; ++i)
{
n = n + (2 * ncip(dim-1, sqrt(R*R - i*i)));
}
return n;
}