我知道this和this,但我再次问,因为现在第一个链接已经很老了,第二个链接似乎没有得出确凿的答案。是否已达成共识?
我的问题很简单:
我有一个DO
循环,其中包含可能并发运行的元素。我使用哪种方法?
下面是在简单立方晶格上生成粒子的代码。
请注意,在CONCURRENT情况下,x,y和z必须是数组,但在OpenMP情况下不是这样,因为它们可以定义为PRIVATE。
所以我使用DO CONCURRENT
(正如我从上面的链接中所理解的那样,使用SIMD):
DO CONCURRENT (i = 1, npart)
x(i) = MODULO(i-1, npart_edge)
Rx(i) = space*x(i)
y(i) = MODULO( ( (i-1) / npart_edge ), npart_edge)
Ry(i) = space*y(i)
z(i) = (i-1) / npart_face
Rz(i) = space*z(i)
END DO
或者我使用OpenMP?
!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(x,y,z)
!$OMP DO
DO i = 1, npart
x = MODULO(i-1, npart_edge)
Rx(i) = space*x
y = MODULO( ( (i-1) / npart_edge ), npart_edge)
Ry(i) = space*y
z = (i-1) / npart_face
Rz(i) = space*z
END DO
!$OMP END DO
!$OMP END PARALLEL
我的测试:
将64粒子放入10号方框中:
$ ifort -qopenmp -real-size 64 omp.f90
$ ./a.out
CPU time = 6.870000000000001E-003
Real time = 3.600000000000000E-003
$ ifort -real-size 64 concurrent.f90
$ ./a.out
CPU time = 6.699999999999979E-005
Real time = 0.000000000000000E+000
将100000个颗粒放在100面的盒子中:
$ ifort -qopenmp -real-size 64 omp.f90
$ ./a.out
CPU time = 8.213300000000000E-002
Real time = 1.280000000000000E-002
$ ifort -real-size 64 concurrent.f90
$ ./a.out
CPU time = 2.385000000000000E-003
Real time = 2.400000000000000E-003
使用DO CONCURRENT
构造似乎给了我至少一个数量级更好的性能。这是在i7-4790K上完成的。此外,并发的优势似乎随着大小的增加而减少。
答案 0 :(得分:3)
DO CONCURRENT本身不进行任何并行化。编译器可以决定使用线程并行化它或使用SIMD指令。对于线程,您经常需要指示它这样做。或者(通常!)它只是将其视为常规DO并使用SIMD,如果它将它们用于常规DO。
OpenMP也不仅仅是线程,编译器可以根据需要使用SIMD instructuons。还有omp simd
指令,但这只是建议编译器使用SIMD,可以忽略它。
你应该尝试,测量和看到。没有一个明确的答案。甚至对于给定的编译器来说,所有编译器都没有。
我的做法是使用OpenMP并尝试确保编译器矢量化(SIMD)它能做什么。特别是因为我无论如何都在我的程序中使用OpenMP。 DO CONCURRENT仍然需要证明它确实有用。我还不相信。