我习惯性地编写具有大量功能的代码,我觉得它更清晰。但是现在我在Fortran中编写了一些需要非常高效的代码,我想知道过度使用函数是否会降低它的速度,或者编译器是否会解决正在发生的事情并进行优化?
我知道在Java / Python等中,每个函数都是一个对象,因此创建大量函数需要在内存中创建它们。我也知道在Haskell中,函数相互减少,所以它没什么区别。
有没有人知道Fortran的情况?使用intent / pure函数/声明更少的局部变量/其他任何东西是否有区别?
答案 0 :(得分:9)
函数调用会为基于堆栈的语言(如Fortran)带来性能成本。他们必须添加到堆栈等。
因此,如果可能的话,大多数编译器都会尝试积极地内联函数调用。大多数情况下,编译器会在是否在程序中内联某些函数时做出正确的选择。
这种自动内联过程意味着编写函数没有额外的成本(根本)。
这意味着您应该尽可能干净地编写代码,并且编译器可能会为您执行这些优化。更重要的是,解决问题的整体策略是最有效的,而不是担心函数调用的性能。
答案 1 :(得分:2)
只需以最简单,结构最好的方式编写代码,然后在编写和测试时,您可以对其进行分析,以查看是否存在需要优化的热点。只有在那时你才应该关注微优化,如果你的编译器正在完成它的工作,这甚至可能都是不必要的。
答案 2 :(得分:1)
我整个上午都在调整一个由混合C和Fortran组成的应用程序,当然它使用了很多功能。我发现的(以及我通常发现的)并不是函数很慢,但某些函数调用(其中很少有)根本不需要完成 < / em>的。例如,清除内存块,只是为了整洁,但要以高频率进行。
这不是语言的功能,也不是内联的功能。函数调用可能 free ,你仍然会遇到调用树往往比必要的更浓密的问题。你需要找出修剪它的地方。 This is the "profiling" method I rely on.
无论你做什么,找出需要修复的内容。别猜。许多人并不认为这类问题是猜测,但当他们发现自己会问“这会起作用吗会有帮助吗?”时,他们会在黑暗中捅,而不是找出问题所在。一旦他们知道问题所在,修复就很明显了。
答案 3 :(得分:0)
通常,Fortran中的子例程/函数调用开销很小。虽然语言标准没有指定参数传递机制,但典型的实现是“通过引用”,因此不涉及复制,只设置新的过程。在大多数现代架构中,这几乎没有开销。选择好的算法通常比微优化更重要。
关于调用快速的例外可能是编译器必须创建临时数组的情况,例如,如果实际参数是非连续的数组子部分,并且被调用的过程参数是一个简单的连续数组。假设伪参数是dimension(:)。使用维数(:)数组调用它很简单。如果您在调用中请求非单位步幅,例如,数组(1:12:3),则该数组是非连续的,并且编译器可能需要创建临时副本。假设实际参数是dimension(:,:)。如果调用具有数组(:,j),则子数组是连续的,因为在Fortran中,第一个索引在内存中变化最快,不需要副本。但是数组(i,:)是非连续的,可能需要临时副本。
有些编译器可以选择在需要临时阵列副本时发出警告,以便您可以根据需要更改代码。