Enr*_*lis 3 performance fortran subroutine multidimensional-array dynamic-memory-allocation
从大约两年前开始,我对Fortran完全陌生,因此我过度使用SUBROUTINE了无参数的s和共享数据,因此这些过程对实际参数进行了计算,可通过USE语句使用。现在,我需要重用其中一些过程(想想从一个体积中的向量场计算一个体积,一个大 DIMENSION(:,:,:)数组中的差异,将三个大 DIMENSION(:,:,:)数组粘合成一个派生类型),我想要
SUBROUTINE秒,但删除USE声明和使用IN/ OUT/ INOUT哑元(容易),或FUNCTIONs 转换它们(因为我必须学习一点,所以难度较小)我想了解一下,两种方法的性能可能有所不同。在下面的MWE中,我编写了3个过程来进行相同的计算,但是我不知道如何选择一个或另一个。我也不知道是否可以采用其他方法。
需要注意的是,我程序中所有3级实际数组都是ALLOCATABLE并且必须是。
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
Run Code Online (Sandbox Code Playgroud)
编辑
在执行CFD的程序中,我使用了几个3级大数组。这些数组彼此交互,因为对其中的一些执行了计算(而不仅仅是逐点+/ -/ *,...),从而获得了其他数组。考虑通过示例中的四个过程之一B来计算哪个A,然后将A其用于升级A = A + B。我以为上面的四个选项可以完成相同的任务,我是否错了?从这个意义上讲,A = A + myfun(A)如果选择函数方法,我可以简单地调用。
EDIT2
实际的派生类型以及那个大的rank-3数组,还有其他六个字段(标量和小的static数组);此外,这种类型的大多数变量都是数组,例如 TYPE(blk3d), DIMENSION(n) :: A。
在子程序或函数之间进行选择通常应基于结果的使用方式以及对读者的清楚程度。
您要关心的是不必要地复制了多少次数据。对于大型阵列,您可能希望减少这种情况。
忽略该过程中的实际工作,myfun将第二次复制数据,并且(可能)进行两次分配。首先,函数结果变量被分配,并将数据复制到该变量。然后再返回到调用方,如果B%values的形状与结果不同,并重新复制数据,则将重新分配B%values,然后释放函数结果。
mysub和mysub2没有额外的分配/复制,并且几乎等效,尽管对mysub2的调用可能需要一些额外的工作来在堆栈上设置描述符。如果子例程进行任何实际工作,我希望这会带来噪音。
在mysub和mysub2之间进行选择实际上取决于实际应用程序中的清晰度。除非您希望拥有这些数组,否则仅具有一个组件的派生类型似乎是不现实的。