kdb*_*kdb 7 arrays fortran return-value return-by-reference return-by-value
在现代Fortran中是否有可能从一个函数返回一个数组,其性能等同于一个子例程填充一个作为参数传递的数组?
考虑例如作为简单的例子
PROGRAM PRETURN
INTEGER :: C(5)
C = FUNC()
WRITE(*,*) C
CALL SUB(C)
WRITE(*,*) C
CONTAINS
FUNCTION FUNC() RESULT(X)
INTEGER :: X(5)
X = [1,2,3,4,5]
END FUNCTION FUNC
SUBROUTINE SUB(X)
INTEGER :: X(5)
X = [1,2,3,4,5]
END SUBROUTINE SUB
END PROGRAM PRETURN
Run Code Online (Sandbox Code Playgroud)
这里的行C = FUNC()将从函数返回值中复制值,然后从堆栈中丢弃返回的数组.子程序版本CALL SUB(C)将C直接填充,避免额外的应对步骤和与临时阵列相关的内存使用 - 但在表达中使用是SUM(FUNC())不可能的.
但是,如果编译器实现选择在堆上分配所有数组,则只需更改底层指针即可分配返回值C,从而在两个版本之间产生相同的性能.*
这些优化是由通用编译器完成的,还是有其他方法来获得函数语义而没有性能开销?
*使用可分配数组会更加明显,但这会遇到编译器支持问题.默认情况下,英特尔fortran在分配不同大小的数组时不会(重新)分配数组,但通过使用ALLOCATE(C, SOURCE=FUNC())语句可以产生相同的效果.Gfortran同时在赋值时执行自动分配,但是有一个错误可以防止ALLOCATE语句从SOURCE参数派生出来,而修复程序尚未包含在二进制版本中.
Fortran标准没有提到实现该语言中几乎所有内容的实际机制.该语言的语义是在赋值开始之前完全评估函数结果.如果一个人将目标作为输出传递,那么如果函数由于某种原因没有完成,那么变量可能会被部分修改.编译器可能能够进行足够的重叠分析以进行一些优化.我很确定英特尔Fortran没有这样做 - 语义限制很重要.
你的例子是一个玩具程序 - 更有趣的问题是,如果有生产应用程序,这样的优化是适用和值得的.
我将评论英特尔Fortran将更改其分配给可分配阵列的默认行为,以便从版本17开始,将按照标准的规定进行自动重新分配.
| 归档时间: |
|
| 查看次数: |
1016 次 |
| 最近记录: |