Fortran - 功能与子程序性能

时间:2018-04-02 09:01:37

标签: performance multidimensional-array fortran dynamic-memory-allocation subroutine

几年前,我对Fortran完全不熟悉,我过度使用了没有参数的SUBROUTINE和共享数据,因此这些程序对实际参数进行了计算,可通过{ {1}}陈述。现在我需要重用其中一些程序(想想从该卷中的向量字段计算卷中的差异, USE数组,3 big < / strong> DIMENSION(:,:,:)数组在派生类型中粘在一起),我想要

  • 保留DIMENSION(:,:,:)个但删除SUBROUTINE语句并使用USE / IN / OUT虚拟参数(简单),或
  • INOUT s中对它们进行转换(因为我要研究一下,所以稍微努力一点)

我想这两种方法的表现可能会有所不同,我想了解。在下面的MWE中,我编写了3个程序来进行相同的计算,但我不知道应该如何选择其中一个;我不知道是否会采取其他方法。

作为一个注释,我的程序中所有排名3的实际数组都是FUNCTION,必须如此。

ALLOCATABLE

修改 在我做CFD的程序中,我使用了几个rank-3大型数组。这些数组在计算中相互交互(不仅仅是逐点PROGRAM mymod IMPLICIT NONE TYPE blk3d REAL, DIMENSION(:,:,:), ALLOCATABLE :: values END TYPE blk3d TYPE(blk3d) :: A, B INTEGER, PARAMETER :: n = 2 INTEGER :: i ALLOCATE(A%values(n,n,n)) A%values = RESHAPE([(i/2.0, i = 1, PRODUCT(SHAPE(A%values)))], SHAPE(A%values)) print *, A%values ! 1st way B = myfun(A) print *, B%values DEALLOCATE(B%values) ! 2nd way ALLOCATE(B%values(n,n,n)) CALL mysub(A, B) print *, B%values DEALLOCATE(B%values) ! 3rd way ALLOCATE(B%values(n,n,n)) CALL mysub2(A, B%values) print *, B%values CONTAINS FUNCTION myfun(Adummy) RESULT(Bdummy) IMPLICIT NONE TYPE(blk3d), INTENT(IN) :: Adummy TYPE(blk3d) :: Bdummy ALLOCATE(Bdummy%values, mold = Adummy%values) Bdummy%values(:,:,:) = 2*Adummy%values END FUNCTION myfun SUBROUTINE mysub(Adummy, Bdummy) IMPLICIT NONE TYPE(blk3d), INTENT(IN) :: Adummy TYPE(blk3d), INTENT(INOUT) :: Bdummy Bdummy%values(:,:,:) = 2*Adummy%values END SUBROUTINE mysub SUBROUTINE mysub2(Adummy, Bdummy) IMPLICIT NONE TYPE(blk3d), INTENT(IN) :: Adummy REAL, DIMENSION(:,:,:), INTENT(OUT) :: Bdummy Bdummy(:,:,:) = 2*Adummy%values END SUBROUTINE mysub2 END PROGRAM mymod / + / -,......),对其中一些进行计算以获得其他数组。考虑*,它是基于B通过示例中的4个过程之一计算的,然后用于A本身升级A。我错误地认为上面的4个选项可以完成相同的任务吗?从这个意义上说,如果我选择函数方法,我可以简单地调用A = A + B

EDIT2 实际的派生类型,以及那个大的rank-3数组,有六个其他字段(标量和小静态数组);此外,这种类型的大多数变量都是数组,例如 A = A + myfun(A)

1 个答案:

答案 0 :(得分:4)

在子程序或函数之间进行选择通常应该基于您将如何使用结果以及它对读者的清晰程度。

您想要关注的是数据被不必要地复制多少次。对于大型数组,您可能希望减少它。

忽略程序中的实际工作,myfun第二次复制数据,并(可能)进行两次分配。首先,分配函数结果变量并将数据复制到它。然后返回调用者,如果B%值与结果的形状不同并再次复制数据,则会重新分配B%值,然后取消分配函数结果。

mysub和mysub2没有这个额外的分配/复制并且非常相同,尽管对mysub2的调用可能需要一些额外的工作来在堆栈上设置描述符。如果子程序有任何实际功能,我希望它是噪音。

在mysub和mysub2之间进行选择实际上取决于它在实际应用程序中的清晰程度。只有一个组件的派生类型似乎不切实际,除非你想要有一个这样的数组。