C - 嵌套在 OpenMP 中的 LOPS



使用 openmp 将并行化到 3 个嵌套的循环的正确方法是什么? 这边:

#pragma omp parallel for
for (i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
for(k=0;k<SIZE;k++)
mresult[i][j]=mresult[i][j] + matrixa[i][k]*matrixb[k][j];

或者这样

#pragma omp parallel for
for (i=0;i<SIZE;i++)
#pragma omp parallel for
for(j=0;j<SIZE;j++)
#pragma omp parallel for
for(k=0;k<SIZE;k++)
mresult[i][j]=mresult[i][j] + matrixa[i][k]*matrixb[k][j];

第二个是严格不正确的,因为存在竞争条件。此外,嵌套parallel通常是一个坏主意,因为它通常会生成比内核更多的线程,从而导致性能不佳。

如果第一行足够大以公开足够的并行工作,则第一行就可以SIZE。通常,并行化最外层循环是最好的,因为相同的并行化开销需要做更多的工作。如果最外层的循环没有足够的并行性,可以考虑添加collapse(2)- 这是并行化循环的正确方法,尽管在这种情况下不是必需的。

综上所述,如果您想要性能矩阵乘法,请使用 tim18 指示的库。从矩阵乘法中获得最佳效率非常复杂,超出了本答案的范围。

正如 Z-Boson 指出的那样,您的第一个版本也是不正确的,因为默认情况下内部循环变量是共享的。您可以将它们标记为private(j,k)或更好,但只需在循环中定义它们,无论如何都要清晰得多:

#pragma omp parallel for
for (int i=0;i<SIZE;i++)
for (int j=0;j<SIZE;j++)
for (int k=0;k<SIZE;k++)

这两种方法都无法达到netlib gemm线程实现的效率。毫无疑问,这已经被更详细地讨论了很多次。 如果你的情况足够大,对并行性感兴趣,除了像 nvidia 这样的一些专门的架构之外,外循环将足够大,以使每个线程在几乎相等的连续内存块上保持忙碌,并且你不会希望阻止编译器在内部循环上应用单线程优化。