为什么解释型语言运行速度慢?

48

我正在阅读有关解释性语言的优缺点,其中最常见的缺点之一是速度较慢,但为什么解释性语言的程序会很慢呢?


请参阅类似的问题:https://dev59.com/rXM_5IYBdhLWcg3wXx5N - Sasha Chedygov
2
我实际上不同意普遍的假设,即解释性语言很慢。什么会使一种语言变慢呢? - Peter Lindqvist
5
@Peter: 在解释执行下,一个紧密的循环通常会比编译执行慢。这并不妨碍我构建一个设计不良的编译程序,其表现不如执行同样任务的解释程序,也不保证我能够编写与解释器代码几乎一样快的编译代码。权衡在各个方面都存在。 - dmckee --- ex-moderator kitten
可能是解释型语言的优缺点的重复问题。 - ggdx
@ggdx:不,这不是重复的。另一个问题问是否有关系,而这个问题明确要求实现原因。 - Lothar
15个回答

85

本地程序使用为其运行的处理器编写的指令来运行。

解释性语言就是这样,“解释”。某种形式的指令被读取并由运行时解释,随后执行本机机器指令。

可以这样想。如果你能用母语与某人交流,那通常比需要一个翻译将你的语言翻译成另一种语言让听众理解更快。

请注意,我上面所描述的是在解释器中运行语言的情况。有许多语言的解释器也有本地链接器,用于构建本机机器指令。速度减慢(然而它的大小可能是多少)只适用于解释上下文。

因此,稍微不准确地说,语言不是慢的,而是它运行的上下文是慢的。

C#不是一种解释性语言,尽管它使用中间语言(IL),但在执行之前,它将被JIT编译为本机指令,因此它具有一些相同的速度降低,但并非全部。但我敢打赌,如果为C#或C++构建了一个完整的解释器,它也会运行得更慢。

只是为了明确,当我说“慢”时,那当然是一个相对的词。


很棒的比喻,我从未这样想过。 - Sasha Chedygov
另外需要注意的是:现在的情况并不像10年前那么糟糕。目前,使用解释性代码可以构建非常有趣的应用程序。我想这完全取决于你正在构建的应用程序类型... - Luis Abreu
1
请注意,将一种编程语言标记为“解释型”并因此认为其“慢”需要谨慎。例如,JavaScript始终是解释执行的(而且速度较慢),但在最近一代JS引擎中,当运行昂贵的计算任务时,它会被编译成本地指令。 - Nickolay

41
所有的回答似乎都忽略了这里真正重要的一点。那就是“解释”代码的实现细节。
解释脚本语言之所以较慢,是因为它们的方法、对象和全局变量空间模型是动态的。在我看来,这才是脚本语言的真正定义,而不是它是否被解释。这就需要在每次访问变量或方法调用时进行许多额外的哈希表查找。这也是它们在多线程和使用全局解释器锁(GIL)方面都很糟糕的主要原因。这个查找过程占据了大部分时间。它是一个痛苦的随机内存查找,在L1/L2缓存未命中时会带来很大的开销。
谷歌的Javascript Core8非常快,几乎达到了C语言的速度,这得益于一个简单的优化:他们将对象数据模型视为固定的,并创建内部代码来像本地编译程序的数据结构一样访问它。当添加或删除新的变量或方法时,整个编译代码都会被丢弃并重新编译。
这个技术在Deutsch/Schiffman的论文《Smalltalk-80系统的高效实现》中有很好的解释。
PHP、Python和Ruby为什么不这样做的问题非常简单:
这个技术的实现非常复杂。
只有谷歌有足够的资金来支付JavaScript,因为快速的基于浏览器的JavaScript解释器是他们十亿美元商业模式的基本需求。

13

将解释器视为一台你没有的计算机的仿真器

简单来说,编译型语言是通过机器指令执行,而解释型语言是由一个程序(用编译型语言编写)执行,该程序读取源代码或字节码,然后基本上模拟了一个假设的计算机,如果该计算机存在,它就可以直接运行程序。

把解释运行时想象成是一种模拟器,可以替代实际上此时你没有的计算机。

当然,这被Java、C#和其他语言所使用的JIT(Just In Time)编译器所复杂化。理论上,它们与“AOT”(“At One Time”)编译器一样好,但在实践中,这些语言运行速度更慢,并且需要在程序运行时拥有编译器,从而占用内存和时间。但是,如果你在这里谈论这些问题,则要准备吸引狂热的JIT辩护者,他们坚称JIT和AOT之间没有理论差异。如果你问他们Java和C#是否像C和C++一样快,那么他们就开始找借口并且稍微冷静下来了。 :-)

因此,在游戏领域,C++完全掌控了最大可用计算资源。

在桌面和Web上,信息导向任务通常由更抽象或至少编译较少的语言完成,因为计算机非常快,问题不需要进行复杂的计算,所以我们可以花费一些时间来达成目标,如市场上的时间、程序员生产力、可靠的内存安全环境、动态模块化和其他强大的工具。


7
这是一个好问题,但在我看来应该稍微改变一下表述,例如:“为什么解释语言比编译语言慢?” 我认为普遍存在这样的误解,即解释语言本身就很慢。解释语言并非慢,但根据使用情况可能比编译版本慢。在大多数情况下,解释语言实际上足够快!“足够快”,再加上使用Python这样的语言提高生产力,就足以证明考虑使用解释语言是有道理的。此外,如果确实需要速度,您可以始终用快速的C实现替换解释程序的某些部分。但是首先要进行测量,并确定速度是否真正是问题,然后再进行优化。

5
循环100次,循环的内容被解释成低级代码100次。不缓存,不重复使用,也不进行优化。
简单来说,编译器只会解释一次成为低级代码。
编辑后:
  • JIT是已经编译过的代码,而不是解释的。只是在后面编译而非预先编译。
  • 我指的是传统的定义,而非现代实际的实现。

当然:http://zh.wikipedia.org/wiki/解释型语言#解释型语言的缺点 - gbn
5
一旦引入JIT编译器,我认为就不能将其称为解释型语言,至少不是纯粹的解释型语言。 - Jon Skeet
1
解释本身就是这样做的。当然,一旦你让它工作起来,你会立即开始考虑做一些更聪明的事情,这也是所有大型的“脚本”语言所做的。许多语言在运行时进行字节码编译,有些使用JIT编译器等等等等。 - dmckee --- ex-moderator kitten
很少有传统解释器会将某些东西“解释为”低级代码的情况。相反,在看到“A=42”的时候,它会注意到语句以变量名开头,查找该变量,注意到接下来的内容是等号,并调用“求值表达式”。该程序将注意到接下来的内容是一个数字,吃掉数字直到下一个非数字,同时累积值(以计算42),然后将其存储到前面计算出地址的变量中。 - supercat
传统解释器只有在执行像 OUT portnum,value 这样的操作时才会“生成低级代码”,例如在需要常量地址的 8080 处理器上使用 out 指令。BASIC 解释器将存储 "OUT" 指令,后跟一个 RET,并将其保存在几个方便使用的字节中,然后调用该例程。 - supercat
显示剩余3条评论

5

除了其他答案之外,还有优化:当您编译程序时,通常不关心编译需要多长时间 - 编译器有很多时间来优化您的代码。当您解释代码时,必须非常快速地完成,因此某些更聪明的优化可能无法实现。


2
一个简单的问题,却没有真正简单的答案。归根结底,所有计算机真正“理解”的只有二进制指令,这也是像C这样的“快速”语言所编译成的内容。
然后,还有虚拟机,它们理解不同的二进制指令(如Java和.NET),但这些指令必须通过即时编译器(JIT)实时翻译为机器指令。这几乎和静态编译器一样快(在某些特定情况下甚至更快,因为JIT比静态编译器更了解代码的使用方式)。
接下来是解释性语言,它通常也有自己的中间二进制指令,但解释器的功能就像一个循环并带有一个大开关声明,在其中有每个指令的情况以及如何执行它。这种抽象层会降低底层机器码的速度。涉及更多的指令、长链的函数调用去完成甚至简单的操作,并且可以争论地认为由于这个原因,内存和缓存并没有被有效地利用。
但解释性语言对于它们使用的目的而言通常足够快。Web应用程序总是被IO(通常是数据库访问)所限制,而这比任何解释器都慢一个数量级。

.NET是一个框架,而不是虚拟机。一个适合虚拟机的语言通常(但并不总是)将代码与硬件和操作系统隔离开,并提供一个抽象的“机器码”,源代码会被编译成这个机器码,然后虚拟机在运行时将其转换为与目标操作系统或硬件兼容的指令。 - 3Dave

1

来自about.com

解释型语言是在运行时处理的。每一行都会被读取、分析和执行。在循环中每次重新处理一行是导致解释型语言如此缓慢的原因。这种开销意味着解释代码运行速度比编译代码慢5-10倍。像Basic或JavaScript这样的解释型语言是最慢的。它们的优点是不需要在更改后重新编译,这对学习编程非常方便。

然而,对于Java和C#等语言来说,5-10倍的速度差异并不一定正确。它们虽然是解释型的,但即时编译器可以为某些操作生成机器语言指令,从而大大加快速度(有时接近编译语言的速度)。


这并不完全正确。C# 和 Java 是编译型语言,但编译成的是 IL(Intermediate Language),而不是本地指令。说它们是解释型语言意味着源代码在运行时进行分析,但这并不适用于 C#(尽管我对 Java 不太熟悉,不能确定是否适用)。 - 3Dave
没错,源代码在运行时并没有被分析,而是编译成了字节码指令。我曾经认为JIT编译(现在大多数Java虚拟机都使用)算作另一种解释形式,但我想这并不是这样的。如果你使用的虚拟机支持解释执行,那么Java确实可以被解释执行,但由于明显的性能原因,大多数虚拟机并不这样做。 - Kaleb Brasee

1

没有所谓的解释性语言。任何语言都可以通过解释器或编译器实现。如今,大多数语言都使用编译器进行实现。

话虽如此,解释器通常较慢,因为它们需要在运行时处理语言或类似语言的东西,并将其翻译成机器指令。编译器只需一次将此转换为机器指令,之后便可直接执行。


1

没错,解释性语言的速度比较慢...

但是,请考虑以下情况。我有一个问题需要解决。在Python中,我花了4分钟解决了这个问题,程序运行时间为0.15秒。然后我尝试用C语言编写它,得到了0.12秒的运行时间,但编写它花费了我1小时的时间。所有这些都是因为解决问题的实际方法是使用哈希表,而哈希表无论如何都会占据运行时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接