从Fortran 2008规范,7.2.1.3.5
如果expr是标量且变量是数组,则将expr视为与其形状相同的数组。 变量,数组的每个元素都等于expr的标量值。
我见过以下编码样式:
答
integer, dimension(3) :: x
do i=1,3
x(i) = 1
enddo
B:
integer, dimension(3) :: x
x(:) = 1
C:
integer, dimension(3) :: x
x = 1
将标量值分配给数组(性能和可读性)的最佳做法是什么?
注意: A 闻起来像Fortran77,我觉得 C 会让未来的读者感到困惑?
答案 0 :(得分:2)
简短的答案:
根据我的经验,案例(A)总是优于Fortran数组语法。然后,情况(C)优于情况(B),仅在特殊情况下,编译器必须做一些额外的工作来理解(:)的含义,否则这两个符号通常是相同的。但是,到目前为止最好的选择似乎是DO CONCURRENT,IFF编译器支持它,比如英特尔Fortran编译器2015,我已经看到了DO CONCURRENT,IFF的性能提升,编译器优化标志已经开启。请注意其他Fortran编译器中的DO CONCURRENT状态,因为它们可能无法优化它并简单地将DO CONCURRENT转换为DO循环,在这种情况下可能会发生性能损失,具体取决于标头的写入方式(下面的详细解答)。
LONG ANSWER:
我今天上午通过以下代码比较了DO-loop与阵列分配与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。
结果:
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