【发布时间】:2011-01-13 00:14:56
【问题描述】:
动态语言是否比静态语言慢,例如,运行时必须一致地检查类型?
【问题讨论】:
标签: performance dynamic-languages
动态语言是否比静态语言慢,例如,运行时必须一致地检查类型?
【问题讨论】:
标签: performance dynamic-languages
没有。
动态语言并不比静态语言慢。事实上,任何语言,无论是否动态,都不可能比另一种语言慢(或更快,就此而言),仅仅是因为一种语言只是一堆抽象的数学规则。你不能执行一堆抽象的数学规则,因此它们永远不会慢(er)或快(er)。
“动态语言比静态语言慢”的说法不仅错误,甚至没有意义。如果英语是一种类型化语言,那么该语句甚至不会进行类型检查。
为了让一种语言能够运行,它必须首先实现。 现在您可以衡量性能,但您不是在衡量语言的性能,而是在衡量执行的性能引擎。大多数语言都有许多不同的执行引擎,具有非常不同的性能特征。例如,对于 C,最快和最慢的实现之间的差异是 100000 倍左右!
此外,您也无法真正衡量执行引擎的性能:您必须首先编写一些代码以在该执行引擎上运行。但现在您测量的不是执行引擎的性能,而是基准代码的性能。这与执行引擎的性能几乎没有关系,当然与语言的性能无关。
一般来说,在设计良好的高性能执行引擎上运行设计良好的代码将产生大致相同的性能,这与语言是静态还是动态、过程式、面向对象还是函数式、命令式还是声明式、惰性语言无关或严格,纯或不纯。
事实上,我认为系统的性能完全取决于花在让它快速上的资金数量,并且完全独立于任何特定的打字规则、编程范式或语言。
以 Smalltalk、Lisp、Java 和 C++ 为例。所有这些都是,或者曾经是,高性能代码的首选语言。他们都在他们身上花费了大量个世纪的工程和研究,以使其速度更快。它们都具有高度调整的专有商业高性能执行引擎。考虑到大致相同的问题,由大致可比的开发人员实现,它们的性能大致相同。
其中两种语言是动态的,两种是静态的。 Java 很有趣,因为尽管它是一种静态语言,但大多数现代高性能实现实际上是动态 实现。 (事实上,几个现代的高性能 JVM 实际上要么是伪装的 Smalltalk VM,衍生自 Smalltalk VM,要么是由 Smalltalk VM 公司编写的。) Lisp 也很有趣,因为它虽然是动态语言,但也有一些(虽然不多) 静态高性能实现。
而且我们甚至还没有开始讨论执行环境的其余部分:现代主流操作系统、主流 CPU 和主流硬件架构都严重偏向于静态语言,甚至到了积极的地步对动态语言有敌意。鉴于现代主流执行环境对于动态语言来说几乎是最坏的情况,它们的实际性能非常惊人,我们只能想象在不那么恶劣的环境中的性能会是什么样子。
【讨论】:
所有其他条件都相同,通常是的。
【讨论】:
首先你必须澄清你是否考虑
通常我们的意思是
,但不是必须的。
类型信息可以帮助 VM 比没有类型信息更快地分发消息,但是随着 VM 中检测单态调用站点的优化,这种差异往往会消失。请参阅此post about dynamic invokation 中的“性能考虑”段落。
编译、解释和字节码 JIT 之间的争论仍然悬而未决。一些人认为字节码 JIT 导致比常规编译更快的执行,因为由于在运行时收集了更多信息,编译更准确。阅读wikipedia entry about JIT 了解更多信息。解释型语言确实比这两种形式或编译中的任何一种都慢。
我不再争辩,开始热烈讨论,我只想指出,两者之间的差距往往越来越小。您可能面临的性能问题可能与语言和 VM 无关,而是与您的设计有关。
编辑
如果你想要数字,我建议你看看The Computer Language Benchmarks。我发现它很有见地。
【讨论】:
在指令级,动态类型语言的当前实现通常比静态类型语言的当前实现慢。
然而,这并不一定意味着程序的实现在动态语言中会变慢 - 有很多记录在案的情况下,同一程序同时用静态和动态语言实现,而动态实现已经证明是快点。例如this study (PDF) 给不同语言的程序员同样的问题并比较了结果。 Python 和 Perl 实现的平均运行时间比 C++ 和 Java 实现的平均运行时间快。
这有几个原因:
1) 代码可以用动态语言更快地实现,留出更多时间进行优化。
2) 高级数据结构(映射、集合等)是大多数动态语言的核心部分,因此更可能被使用。由于它们是语言的核心,因此它们往往被高度优化。
3) 程序员的技能比语言速度更重要——没有经验的程序员可以用任何语言编写慢代码。在上述研究中,每种语言的最快和最慢实现之间存在几个数量级的差异。
4) 在许多问题域中,执行速度主要由 I/O 或语言外部的一些其他因素决定。
5) 算法选择可以使语言选择相形见绌。在“More Programming Pearls”一书中,Jon Bentley 为一个问题实现了两种算法 - 一种是 O(N^3),并在 Cray1 上以优化的 fortran 实现。另一个是 O(N),并在 TRS80 家用微型计算机上用 BASIC 实现(这是在 1980 年代)。 TRS80 的 N > 5000 优于 Cray 1。
【讨论】:
动态语言运行时只需要检查类型偶尔。
但它仍然,通常,较慢。
然而,有些人声称这种性能差距是可以攻击的;例如http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html
【讨论】:
最重要的因素是考虑方法分派算法。对于静态语言,通常为每个方法分配一个索引。我们在源代码中看到的名称实际上并没有在运行时使用,而是出于可读性目的而在源代码中使用。自然地,像 java 这样的语言会保留它们并使它们在反射中可用,但就调用方法而言,它们不会被使用。我将把反思和约束排除在讨论之外。这意味着当调用方法时,runtmne 只需使用偏移量来查找表并调用。另一方面,动态语言使用函数的名称来查找地图,然后调用所述函数。哈希图总是比使用索引查找数组要慢。
【讨论】:
可以合理地假设,因为需要在运行时计算更多的东西。
【讨论】:
实际上,这很难说,因为所使用的许多基准并不具有代表性。随着更复杂的执行环境,如 HotSpot JVM,差异变得越来越不相关。请看以下文章:
Java theory and practice: Dynamic compilation and performance measurement
【讨论】: