Concurrency 我应该何时使用DO CONCURRENT和何时使用OpenMP?
我知道和,但我再次问,因为第一个链接现在已经很旧了,而第二个链接似乎没有得出结论性的答案。有没有达成共识 我的问题很简单: 我有一个Concurrency 我应该何时使用DO CONCURRENT和何时使用OpenMP?,concurrency,fortran,openmp,simd,fortran2008,Concurrency,Fortran,Openmp,Simd,Fortran2008,我知道和,但我再次问,因为第一个链接现在已经很旧了,而第二个链接似乎没有得出结论性的答案。有没有达成共识 我的问题很简单: 我有一个DO循环,其中的元素可以同时运行。我用哪种方法 下面是在简单立方晶格上生成粒子的代码 npart是粒子数 npart_边和npart_面分别沿边和面 空间是晶格间距 Rx、Ry、Rz是位置阵列 x、 y,z是决定晶格位置的临时变量 请注意,不同之处在于,x、y和z在并发情况下必须是数组,但在OpenMP情况下并非如此,因为它们可以定义为私有 因此,我是否使用do
DO
循环,其中的元素可以同时运行。我用哪种方法
下面是在简单立方晶格上生成粒子的代码
- npart是粒子数
- npart_边和npart_面分别沿边和面
- 空间是晶格间距
- Rx、Ry、Rz是位置阵列
- x、 y,z是决定晶格位置的临时变量
do CONCURRENT
(我从上面的链接中了解到,它使用SIMD):
还是使用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上完成的。而且,并发的优势似乎随着大小的增加而减少。DO CONCURRENT本身并不做任何并行化。编译器可能决定使用线程或SIMD指令对其进行并行化。对于线程,您通常必须指示它这样做。或者(通常!)它只是将其视为常规DO,如果它将其用于常规DO,则使用SIMD
OpenMP也不仅仅是线程,编译器可以根据需要使用SIMD指令。还有omp simd
指令,但这只是建议编译器使用simd,可以忽略它
你应该试试看。没有一个明确的答案。即使对于一个给定的编译器,对于所有的编译器也是如此
我的做法是使用OpenMP并尝试确保编译器矢量化(SIMD)。特别是因为我在我的程序中都使用OpenMP。你还需要证明它实际上是有用的。我还不确信。关于x、y和z在DO并发情况下需要是数组的断言不是语言要求。如何实现并发也在很大程度上取决于编译器的能力——惰性编译器可能只是将其实现为普通的串行循环,而没有任何矢量化或并行化。所以答案是。。。“视情况而定。”@IanH你说这不是语言要求是什么意思?我说它们必须是数组,因为否则,这些操作不能同时进行。另外,我还添加了关于性能的编辑信息。那么现在的问题是什么?一般情况下,并发还是OpenMP?或者如何使这段代码运行得更快?这些都是非常不同的问题。当然,一般的答案是使用更快的方法。@IanH好的,我读过了,现在我明白了。因此,这意味着处理器可以按任意顺序执行迭代,这可能是并发的,也可能不是并发的。这确实是一个不好的命名的例子。仅仅因为我们有一个闪亮的新功能:一些
do concurrent
。我已经添加了您之前请求的信息作为编辑。此外,我确实在代码的其他地方使用了openmp,但在那里,并发性没有帮助。ifort-qparallel请求并行化do concurrent。使用上面给出的选项,将只有simd矢量化,这对于您的问题大小似乎更有效。如果内部循环长度最多为100,将其拆分为线程块将消除simd矢量化的大部分优势。块可以在DO CONCURRENT中使用,以避免为局部变量生成数组。假设您在启用超线程的情况下运行,则需要检查线程数小于默认值的并行性能,设置OMP_PLACES=cores,然后才能得出并行效率太低的结论。几乎没有理由期望do concurrent auto parallel执行与OpenMP不同的操作。@tim18在这个问题下给出更好的评论。这个答案是在细节暴露之前写的,根本没有反映出来。@tim18所以如果我在DO
循环中放置块
,每个迭代的局部变量是独立的?这比制作阵列更有效吗?另外,我为什么要将omp设置为不使用超线程?
$ 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