假设我有这些循环:
#pragma omp parallel for
for(int i=0;i<100;++i)
{
// some big code here
#pragma omp parallel for
for(int j=0;j<200;j++)
{
// some small code here
}
}
哪个循环并行运行?哪一个最好并行运行?
这里的要点是:
1-如果i-loop并行运行,因为那里有一些大代码,很有可能CPU缓存在循环的每次迭代中都会命中。
2-如果j-loop并行运行,因为那里没有太多代码,它可能没有达到CPU缓存,但我正在失去并行运行大代码。
我不知道openMP如何并行运行这些for循环所以我可以优化它们?
我的代码应该在windows(visual studio)和ARM Linux上运行。
答案 0 :(得分:1)
如果不启用嵌套(环境变量OMP_NESTED = true),则只有外部循环并行运行。
如果启用嵌套,则两个循环将并行运行,但可能会创建太多线程。
您可以在外部循环上使用omp parallel,并为内部循环使用任务分组多次迭代,例如:
#pragma omp parallel for
for (int i = 0; i<100; i++) {
//big code here
blocksize = 200/omp_get_num_threads();
int j = 0;
while(j < 200) {
int mystart = j; int myend = j+(blocksize-1);
#pragma omp task firstprivate(mystart,myend)
{
//small code here
}
if (j + blocksize >= 200) j = 200 - blocksize;
else (j+=blocksize);
}
#pragma omp taskwait
}
如果你考虑在内循环中使用SIMD,那么它的编写方式与你的内容完全相似:
#pragma omp parallel for
for (int i = 0; i<100; i++) {
//big code here
#pragma omp simd
for (int j = 0; j<200; j++) {
//small code here
}
}
但是这个最新的选项非常具体。基本上强制编译器对循环进行矢量化。
有关该主题的更多信息。在https://software.intel.com/en-us/articles/enabling-simd-in-program-using-openmp40中,您会找到一个使用#pragma omp parallel for simd
的示例。这意味着并行化循环,每个线程将运行其迭代空间并应用矢量化。
这仍然需要启用并行区域的嵌套(OMP_NESTED),并且根据运行时实现,它可以生成多个线程组,每个线程的外部循环最多一个。
答案 1 :(得分:0)
我同意实验是学习并行编程的好方法,你应该尝试多种组合(仅内部,仅外部,两者,其他?),以查看代码的最佳组合。我的答案的其余部分将有希望给你一个提示,为什么最快的方式是最快的。
可以完成嵌套并行区域,但通常不是您想要的。考虑这个question进行类似的讨论。
当选择要并行化的循环时,常见的主题是首先将最外层循环并行化用于多核,并且最内层循环首先用于SIMD。当然有一些警告。并非所有循环都可以并行化,因此在这种情况下,您应该继续进行下一个循环。此外,局部性,负载平衡和错误共享可能会改变哪个循环是最佳的。