我永远不确定应该选择哪种方式并行化嵌套的for循环。
例如,我有以下代码片段:
#pragma omp parallel for schedule(static)
for(int b=0; b<bSize; b++)
for(int n=0; n<N; n++) o[n + b*N] = b[n];
#pragma omp parallel for collapse(2) schedule(static)
for(int b=0; b<bSize; b++)
for(int n=0; n<N; n++) o[n + b*N] = b[n];
在第一个代码段中,我使用parallel for
(由于使用了第一个触摸策略,因此使用schedule(static)
)。在某些代码中,我看到人们在其他代码中大多使用塌陷子句来嵌套嵌套的for循环,而从未使用过,而是使用简单的parallel for
将嵌套的for循环并行化。这是更习惯还是两个版本之间有区别?某些人从不使用collapse(n)
是有原因的吗?
答案 0 :(得分:3)
与HPC中的所有内容一样,答案是“取决于...”
这取决于
对于所有在相同时间运行的迭代静态调度,除非可以保证工作共享的迭代数除以线程数,否则需要确保可用迭代数约为10倍由于潜在的不平衡,保证90%效率的线程数。因此,如果您有16核计算机,则需要> 160次迭代。如果“ bSize”很小,则使用折叠生成更多可用的并行性将有助于提高性能。 (在最坏的情况下,请想象“ bSize”小于线程数!)
另一方面,正如@ tim18指出的那样,如果您可以向量化内部循环,同时又保持足够的并行度,那可能是更好的选择。
另一方面,没有什么可以阻止您同时进行这两项工作:-
#pragma omp for simd collapse(2)
for(int b=0; b<bSize; b++)
for(int n=0; n<N; n++) o[n + b*N] = b[n];
如果您的内部循环确实很小(并且可以向量化),那么您肯定要对其向量化,因为与并行性不同,向量化可以减少您使用的CPU总时间,而不仅仅是在内核之间移动。