是否应使用 INTENT 关键字加快代码速度?

Should the use of the INTENT keyword speed the code up?

此问题基于对 post Fortran intent(inout) versus omitting intent 的回答,即用户 Vladimyr @Vladimyr 的回答。

他说“<...> Fortran 将数据复制到内存的连续部分,并将新地址传递给例程。返回后,数据将复制回其原始位置。通过指定 INTENT , 编译器可以知道跳过其中一个复制操作。"

我完全不知道这一点,我以为 Fortran 和 C 完全一样通过引用传递。 第一个问题是,为什么 Fortran 会这样做,这个选择背后的基本原理是什么?

作为第二点,我对这种行为进行了测试。如果我理解正确,使用 INTENT(IN) 将节省将数据复制回原始位置所花费的时间,因为编译器确定数据没有被更改。

我试过这段代码

function funco(inp) result(j)
  !!  integer, dimension(:), intent (in) :: inp
  integer, dimension(:):: inp
    integer, dimension(SIZE(inp)) :: j ! output
    j = 0.0       !! clear whole vector
    N = size(inp)
    DO i = 1, N
      j(i) = inp(i)
   END DO
end function

program main
    implicit none


interface
    function funco(inp) result(j)
  !!  integer, dimension(:), intent (in) :: inp
    integer, dimension(:) :: inp
    integer, dimension(SIZE(inp)) :: j ! output
    end function
   end interface 

 
    
    integer, dimension(3000) :: inp , j
 !!   integer, dimension(3000) :: funco
    integer :: cr, cm , c1, c2,  m
    real :: rate, t1, t2

! Initialize the system_clock
  CALL system_clock(count_rate=cr)
  CALL system_clock(count_max=cm)
CALL CPU_TIME(t1)
  rate = REAL(cr)
  WRITE(*,*) "system_clock rate ",rate



    inp = 2
DO m = 1,1000000
     j = funco(inp) + 1
END DO

    CALL SYSTEM_CLOCK(c2)

 CALL CPU_TIME(t2)
WRITE(*,*) "system_clock : ",(c2 - c1)/rate
  WRITE(*,*) "cpu_time     : ",(t2-t1)
end program

函数复制一个数组,在主体中重复多次

根据上面的说法,复制回数组所花费的时间应该以某种方式显示出来。

system_clock rate    1000.00000    
 system_clock :    2068.07910    
 cpu_time     :    9.70935345 

但无论是否使用 INTENT,结果都几乎相同。

谁能分享一下这两点,为什么 Fortran 执行额外的复制(一开始看起来效率不高)而不是通过引用传递,并且确实 INTENT 节省了时间复制操作?

您所指的答案是关于传递某些特定类型的小节,而不是整个数组。在那种情况下,临时副本 可能 是必要的,具体取决于功能。您的函数使用并假定了形状数组,即使您非常努力地尝试也不需要临时数组。

作者(不是我)可能想到的例子是

module functions
  implicit none
contains

  function fun(a, n) result(res)
    real :: res
    ! note the explicit shape !!!
    integer, intent(in) :: n
    real, intent(in) :: a(n, n)
    integer :: i, j
    
    do j = 1, n
      do i = 1, n
        res = res + a(i,j) *i + j
      end do
    end do
  end function
end module

program main
  use functions
  
  implicit none 
  
  real, allocatable :: array(:,:)
  real :: x, t1, t2
  integer :: fulln
  
  fulln = 400
  
  allocate(array(1:fulln,1:fulln))
  
  call random_number(array)
  
  call cpu_time(t1)
  
  x = fun(array(::2,::2),(fulln/2))
  
  call cpu_time(t2)
  
  print *,x
  
  print *, t2-t1
  
end program
 

与 Gfortran 中的 intent(inout) 相比,此程序在 intent(in) 中要快一些(在 Intel 中不是那么快)。但是,使用假定的形状数组 a(:,:) 甚至更快。然后不执行复制。

当 运行 没有运行时检查时,我也在 gfortran 中得到一些奇怪的未初始化访问。我不明白为什么。

当然这是一个人为的例子,在生产程序中有真实的案例,其中制作数组副本然后 intent(in) 可以有所作为。