在 Fortran 中放置数组分配的建议做法



关于我们应该在哪里分配数组,有哪些建议或最佳实践?

例如,如果我有一个(我的简化版本(程序,如图所示,我将在主程序中分配输出变量(感兴趣的变量(。这个主程序调用子程序foo,而子程序又调用子程序foo2,谁做实际的计算。 我的问题是应该在哪里进行分配的最佳/推荐做法是什么。

  • 如果foo2进行实际计算,它应该分配数组吗?
  • 如果foo调用foo2foo应该分配数组并foo2只是计算?
  • 我应该编写一个新的函数/子例程来分配数组吗?
  • 还是最好在主程序上分配并将数组传递为 假设形状?

如果它很重要,我有一个名为 global 的模块,它包含主程序上的派生类型,以及代码的主要参数,例如每个数组的大小(NiNj、公差等(

program main
use global
implicit none
type(myVar_) :: ans
Ni = 10
Nj = 20
if (allocated(ans%P)) deallocate(ans%P)
allocate(ans%P(1:Ni, 1:Nj))
call foo(ans)
print *, P
end program main
module global
integer, parameter :: dp=kind(0.d0)
integer :: Ni, Nj
type myVar_
real(dp), allocatable :: P(:,:)
end type myVar_
end module global
subroutine foo(myVar)
use global
implicit none
type(myVar_) :: myVar
call foo2(myVar%P)
end subroutine
subroutine foo2(P)
use global
implicit none
real(dp), intent(inout) :: P(:,:)
! do calculations for P
end subroutine foo2

什么

出于性能原因,避免在低级子例程和函数中进行分配确实是一种很好的做法。从 [1] 可以看出,简单的添加大约需要 1-3 个 CPU 周期,分配和解除分配对("小"阵列(可能需要 200-500 个 CPU 周期。

我建议您使用"work"变量作为输入并可能就地操作(即用结果覆盖输入(编写一个子例程,例如

subroutine do_computation(input,output,work1,work2)
work1 = ...
work2 = ...
output = ...
end subroutine

您可以创建一个包装器函数,为方便起见进行分配:

subroutine convenient_subroutine(input,output)
allocate(work1(...),work2(...)
call do_computation(input,output,work1,work2)
deallocate(work1,work2)
end subroutine

当性能不重要时,您可以调用convenient_subroutine,但否则,您可以调用尝试在循环迭代之间和不同的其他子例程之间共享工作数组do_computation

[1] http://ithare.com/infographics-operation-costs-in-cpu-clock-cycles/

最新更新