是什么让 Fortran 快速?

计算科学 表现 正则 语言
2021-12-21 19:38:23

Fortran 在数值编程中占有特殊的地位。你当然可以用其他语言制作又好又快的软件,但是尽管 Fortran 已经老了,但它的性能仍然很好。此外,在 Fortran 中制作快速程序更容易。我用 C++ 编写了快速程序,但你必须更加小心指针别名之类的事情。所以,这一定是有原因的,而且是一个非常技术性的原因。是因为编译器可以优化更多吗?我真的很想知道技术细节,所以如果我使用另一种语言,我可以考虑这些事情。

例如,我知道 - 或者我认为 - 一件事是标准指定指针在内存中始终是连续的,这意味着更快的内存访问。我相信你可以在 C++ 中通过给编译器一个标志来做到这一点。通过这种方式,它有助于了解 Fortran 的优点,因此如果使用另一种语言,我们可以模仿这一点。

4个回答

语言设计者面临许多选择。 Ken Kennedy强调了两个:(1)更好的抽象和(2)更高或更低级别(更少或更多类似机器)的代码。虽然 Haskell 和 Scheme 等函数式语言侧重于前者,但 Fortran 和 C/C++ 等传统科学计算语言侧重于后者。说一种语言比另一种语言快通常是一种误导:每种语言都有自己擅长的问题领域。Fortran 在基于数组的数字代码领域比其他语言表现得更好,这有两个基本原因:它的数组模型和它的明确性。

阵列模型

Fortran 程序员主要进行数组操作。为此,Fortran 促进了其他语言中没有的几种编译器优化。最好的例子是向量化:知道数据布局使编译器能够在数组上调用汇编级内在函数。

语言明确性

虽然看起来更简单的语言应该比更复杂的语言编译“更好”,但事实并非如此。当一个人用汇编语言编写代码时,编译器无能为力:它所看到的只是非常细粒度的指令。Fortran 仅在对基于数组的计算产生真正回报的情况下才需要明确性(因此,程序员需要做更多的工作)。Fortran 使用简单的数据类型、基本的控制流和有限的命名空间;相比之下,它不会告诉计算机如何加载寄存器(这对于实时来说可能是必需的)。Fortran显式的,它支持诸如完整类型推断之类的事情,这有助于新手入门。它还避免了经常使 C 变慢的一件事:不透明的指针

Fortran 可能很慢

Fortran对于每项任务都不是很快:这就是为什么没有多少人使用它来构建 GUI 甚至是高度非结构化的科学计算。一旦你离开了图形、决策树和其他领域的数组世界,这种速度优势很快就会消失。有关一些示例和数字,请参阅计算机语言基准

Fortran 的设计允许编译器在某些情况下执行更强的优化,这些优化通常不适用于 C。

一个著名的例子是别名的处理。在 Fortran 中,您只能通过与该内存区域关联的特定符号来访问特定的内存区域。这种知识允许编译器在缓存时使用智能技巧:它知道值是否可能发生变化。在 F90 之前,这很容易得到验证。当 Fortran 90 引入pointers时,假设不再成立:您可以通过两个(或更多)符号访问相同的内存区域。这就是为什么您必须指定target要通过指针寻址的数组的原因。

另一个有趣的事实是,许多结构允许编译器在没有用户干预的情况下执行并行化。由于 Fortran 作为一种语言相对“平台不可知论”,这种奢侈是可能的。

还有许多其他类似的微妙技巧。此外,请记住今天没有人使用 Fortran,除了数值计算,这意味着 Fortran 编译器的核心特性和卖点是生成的代码速度。因此,供应商专注于这一点。

不过,您也可以使用其他语言生成高性能代码。然而,它可能需要特别小心或人工干预。然而,一般的观点是,在出现问题之前性能不是问题,而且人工时间比计算机时间昂贵得多。因此,编码实践应该专注于节省人力时间,而不是计算机时间。

我不认为 Fortran 与金属如此接近(请参阅其他答案),但它往往很容易优化。循环很简单,并且该语言很容易支持矢量化扩展(好吧,当我在第一份工作中使用它时,我们的目标是广泛的矢量大铁)。

还有很大的惯性因素。很多数字代码都在 Fortran 中,因此高端服务器和超级计算机的构建者确保他们编写了良好的优化 Fortran 编译器。编译器很好(即使在相对缺乏高质量编译器的机器上),因此用户继续使用 Fortran,甚至在其中编写新代码。所以建设者确保他们的下一代有好的编译器,等等......

小心这里的城市神话。如果两个编译器生成相同的汇编代码,那么生成的程序将具有相同的性能。

对于任何给定的逻辑,都有一个汇编语言程序可以最大限度地减少其执行时间。该程序不关心哪个编译器生成它。

也就是说,编译语言的存在是为了让程序员的生活更轻松。这样做的部分成本是它们可能会诱使用户使用不会导致最短执行时间的功能。这方面的主要例子是new在 C++ 中。(它有多慢 - 它只有三个字符?)它实际上是在请求你动态分配内存,而不是关注运行时成本。如果这就是您想要做的,那就太好了,但 Fortran 可能会更快,因为它不会吸引您这样做。

但除此之外,我从来没有见过一个程序在最初编写时没有很大的性能改进空间,而编译器永远无法为您清理这种性能。例如,花费大量时间调用exp和/或log重复使用相同的参数。作为另一个示例,调用 DGEMM 来乘以矩阵并发现大部分时间都用于调用 LSAME 只是为了破译其输入字符参数。

这与人们说 Fortran 由于指针别名或循环展开而更快的同时。这就像说保时捷制造的公共汽车肯定会比雪佛兰制造的公共汽车快。需要有一点常识。