简短回答:
根据我的经验,情况 (A) 始终优于 Fortran 数组语法。然后,情况 (C) 优于情况 (B),仅在特殊情况下编译器必须做一些额外的工作来理解 (:) 的含义,否则这两种表示法通常是相同的。但是,到目前为止,最好的选择似乎是 DO CONCURRENT,IFF 编译器支持它,例如 Intel Fortran 编译器 2015,并且我已经看到 DO CONCURRENT,IFF 编译器优化标志打开时的性能提升。请注意其他 Fortran 编译器中的 DO CONCURRENT 状态,因为它们可能不会对其进行优化,而只是将 DO CONCURRENT 转换为 DO 循环,在这种情况下可能会发生性能损失,具体取决于标头的编写方式(下面的长答案)。
长答案:
今天早上,我根据自己的知识,使用以下代码比较了 DO 循环、数组分配和 DO CONCURRENT:
program performance_test
implicit none
integer :: i,j,k, nloop = 10**4
integer, dimension(:,:), allocatable :: variable
real*8 :: tstart,tend
allocate(variable(nloop,nloop))
call cpu_time(tstart)
do k = 1,10
variable = 0.0
end do
call cpu_time(tend)
write(*,*) tend-tstart
call cpu_time(tstart)
do k = 1,10
do j = 1,nloop
do i = 1,nloop
variable(i,j) = 0.0
end do
end do
end do
call cpu_time(tend)
write(*,*) tend-tstart
call cpu_time(tstart)
do k = 1,10
do concurrent (j = 1:nloop, i = 1:nloop)
variable(i,j) = 0.0
end do
end do
call cpu_time(tend)
write(*,*) tend-tstart
call cpu_time(tstart)
do k = 1,10
do i = 1,nloop
do j = 1,nloop
variable(i,j) = 0.0
end do
end do
end do
call cpu_time(tend)
write(*,*) tend-tstart
call cpu_time(tstart)
do k = 1,10
do concurrent (i = 1:nloop, j = 1:nloop)
variable(i,j) = 0.0
end do
end do
call cpu_time(tend)
write(*,*) tend-tstart
end program performance_test
编译器是Intel Fortran 2015。
Result:
无论编译器优化标志是打开还是关闭,DO CONCURRENT 和简单的 DO 循环都优于 Fortran 数组语法(至少在这个示例中,据我所知),但仅当它是在考虑 Fortran 列顺序的情况下完成的。从技术上讲,我不认为人们可以用 DO CONCURRENT 来谈论按列或按行,就像我在下面使用的那样。由于没有优化标志,DO CONCURRENT 基本上是简单的 DO 循环。通过优化标志,编译器本身将处理循环的顺序。
到目前为止,我在英特尔 Fortran 编译器 2015 中使用 DO CONCURRENT 的经验:在复杂的 DO 循环中,编译器无法轻松解读并发性,与简单的 DO 循环相比,它会带来一些性能提升,并且在其他情况下,它与 DO 循环一样好,应该如此,除非它与 OPENMP 指令结合使用,这会导致今天的灾难,至少就我的实验而言是这样。
没有编译器优化:
array syntax : 4.44602850000000
do-loop, column-wise : 3.82202450000000
do concurrent, column-wise : 3.91562510000000
do-loop, row-wise : 19.1413227000000
do concurrent, row-wise : 19.2817236000000
O2 水平优化:
array syntax : 0.218401400000000
do-loop, column-wise : 0.187201200000000
do concurrent, column-wise : 0.171601100000000
do-loop, row-wise : 0.187201200000000
do concurrent, row-wise : 0.171601100000000