我想并行化这种循环。请注意,每个“calc_block”使用在上一次迭代中获得的数据。
for (i=0 ; i<MAX_ITER; i++){
norma1 = calc_block1();
norma2 = calc_block2();
norma3 = calc_block3();
norma4 = calc_block4();
norma = norma1+norma2+norma3+norma4;
...some calc...
if(norma<eps)break;
}
我试过这个,但加速很小~1.2
for (i=0 ; i<MAX_ITER; i++){
#pragma omp parallel sections{
#pragma omp section
norma1 = calc_block1();
#pragma omp section
norma2 = calc_block2();
#pragma omp section
norma3 = calc_block3();
#pragma omp section
norma4 = calc_block4();
}
norma = norma1+norma2+norma3+norma4;
...some calc...
if(norma<eps)break;
}
我认为这是因为在循环中使用部分的开销。但我不知道如何修复它... 提前谢谢!
答案 0 :(得分:3)
您可以通过在并行区域内移动整个循环来减少开销。因此,用于实现团队的池中的线程只会被“唤醒”一次。这有点棘手,需要仔细考虑变量共享类:
#pragma omp parallel private(i,...) num_threads(4)
{
for (i = 0; i < MAX_ITER; i++)
{
#pragma omp sections
{
#pragma omp section
norma1 = calc_block1();
#pragma omp section
norma2 = calc_block2();
#pragma omp section
norma3 = calc_block3();
#pragma omp section
norma4 = calc_block4();
}
#pragma omp single
{
norma = norm1 + norm2 + norm3 + norm4;
// ... some calc ..
}
if (norma < eps) break;
}
}
sections
和single
结构都有两个隐含的障碍,因此线程会在进入下一个循环迭代之前进行同步。 single
构造重现了程序的先前序列部分。 ...
子句中的private
部分应列出尽可能多的仅与... some calc ...
相关的变量。我们的想法是使用线程局部变量运行串行部分,因为大多数OpenMP实现对共享变量的访问速度较慢。
请注意,由于完全不同的原因,通常加速时间可能不是线性的。例如calc_blockX()
(X
为1
,2
,3
或4
)可能计算强度太低,因此要求非常高内存带宽。如果内存子系统无法同时为所有4个线程提供数据,则加速将小于4.这种情况的一个示例 - this question。