关于性能:为什么解释语言速度慢?

Why are Interpreted Languages Slow?

我在读解释语言的优缺点,最常见的缺点之一是速度慢,但是为什么解释语言的程序速度慢呢?


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

解释语言就是"解释"。另一种形式的指令由运行时读取和解释,运行时反过来执行本机指令。

这样想。如果你能用你的母语和某人交谈,那通常比让一个口译员把你的语言翻译成其他语言让听者理解要快。

请注意,我上面描述的是当一种语言在解释器中运行时的情况。有许多语言的解释程序,也有构建本机机器指令的本机链接器。减速(不管大小)只适用于解释的上下文。

所以,说语言速度慢是有点不正确的,相反,它运行的上下文速度慢。

C语言不是一种解释的语言,即使它使用中间语言(IL),但在执行之前,它会被引向本地指令,所以它有一些相同的速度降低,但不是所有的,但是我敢打赌,如果你为C++或C++建立了一个完全成熟的解释器,它也会运行得更慢。

我说"慢"的时候,这当然是一个相对的词。


所有的答案似乎都忽略了这里真正重要的一点。这是如何实现"解释"代码的细节。

解释脚本语言速度较慢,因为它们的方法、对象和全局变量空间模型是动态的。在我看来,这是对脚本语言的真正定义,而不是解释它的事实。这需要在每次访问变量或方法调用时进行许多额外的哈希表查找。这也是为什么它们在多线程和使用gil(全局解释器锁)方面都很糟糕的主要原因。这种查找是花费大部分时间的地方。这是一个痛苦的随机内存查找,当您丢失一级/二级缓存时,这真的很痛苦。

Google的javascript core8速度如此之快,几乎以C速度为目标进行了简单的优化:他们将对象数据模型视为固定的,并创建内部代码来访问它,就像本机编译程序的数据结构一样。当添加或删除一个新的变量或方法时,整个编译后的代码将被丢弃并重新编译。

在Deutsch/Schiffman的论文《Smalltalk-80系统的有效实现》中,该技术得到了很好的解释。

为什么php、python和ruby不这样做的问题很简单:这种技术的实现非常复杂。

只有谷歌有足够的钱来支付javascript,因为快速的基于浏览器的javascript解释器是他们数十亿美元商业模式的根本需求。


把介入器想象成是一台你没有的机器的仿真器。

简而言之,编译语言是由机器指令执行的,而解释语言是由一个程序(用编译语言编写)执行的,该程序读取源代码或字节码,然后本质上模拟一个假想的机器,如果机器存在的话,它将直接运行程序。

把解释后的运行时想象成一个模拟器,用于一台您目前还没有实际使用的机器。

JIT(Jimtime)编译器显然是复杂的,Java、C等。理论上,它们和"AOT"("一次性")编译器一样好,但在实践中,这些语言运行速度较慢,需要让编译器在程序运行时耗尽内存和时间,从而妨碍了它们的运行。但是如果你在这里说了这些话,那么准备好吸引狂暴的JIT防御者,他们坚持认为JIT和AOT之间没有理论上的区别。如果你问他们Java和C语言是否和C和C++一样快,那么他们就开始找借口和冷静下来。-)

因此,C++完全可以在游戏中使用最大的可用计算量。

在桌面和Web上,面向信息的任务通常是由抽象程度更高或编译程度更低的语言完成的,因为计算机速度非常快,而且问题的计算量不高,因此我们可以将一些时间花在目标上,如上市时间、程序员生产力、可靠的内存安全环境、动态模块等。以及其他强大的工具。


这是一个很好的问题,但在我看来应该有点不同,例如:"为什么解释语言比编译语言慢?"

我认为理解语言本身速度慢是一种常见的误解。解释语言并不慢,但根据用例的不同,可能比编译版本慢。在大多数情况下,解释语言实际上足够快!

"足够快",再加上使用诸如python-over这样的语言提高了生产力,例如,C应该是考虑解释语言的充分理由。此外,如果您真的需要速度,您可以用一个快速的C实现替换解释程序的某些部分。但同样,首先测量并确定速度是否真的是问题所在,然后进行优化。


循环100次,循环的内容被解释为100次低级代码。

不缓存、不重用、不优化。

简单来说,编译器将一次解释为低级代码

编辑,评论后:

  • JIT是编译的代码,不是解释的。只是后来编的,不是事先编的
  • 我指的是经典的定义,而不是现代的实际应用


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


一个简单的问题,没有任何真正简单的答案。归根结底,所有真正"理解"的计算机都是二进制指令,这就是像C这样的"快速"语言被编译成的。

然后是虚拟机,它们理解不同的二进制指令(如Java和.NET),但这些必须由一个只需编译的编译器(JIT)翻译成机器指令。这几乎一样快(在某些特定情况下甚至更快,因为JIT比静态编译器有更多关于代码如何使用的信息。)

还有解释语言,它们通常也有自己的中间二进制指令,但是解释器的功能很像一个循环,其中包含一个大型switch语句,每个指令都有一个case,以及如何执行它。对底层机器代码的这种抽象级别是缓慢的。在解释器中有更多的指令、长的函数调用链来做一些简单的事情,可以说,内存和缓存的使用并没有那么有效。

但是,对于所使用的目的而言,解释语言往往足够快。Web应用程序总是被IO(通常是数据库访问)绑定,IO比任何解释器都慢一个数量级。


没有解释的语言。任何语言都可以由解释器或编译器实现。现在大多数语言都使用编译器实现。

也就是说,解释器通常速度较慢,因为它们需要在运行时处理语言或与之相当接近的内容,并将其转换为机器指令。编译程序只将此转换为机器指令一次,然后直接执行这些指令。


维基百科说,

Interpreting code is slower than running the compiled code because the interpreter must analyze each statement in the program each time it is executed and then perform the desired action, whereas the compiled code just performs the action within a fixed context determined by the compilation. This run-time analysis is known as"interpretive overhead". Access to variables is also slower in an interpreter because the mapping of identifiers to storage locations must be done repeatedly at run-time rather than at compile time.

请参阅此IBM文档,

Interpreted program must be translated each time it is executed, there is a higher overhead. Thus, an interpreted language is generally more suited to ad hoc requests than predefined requests.

在Java中,尽管它被认为是一种解释性语言,但它使用JIT(准时编译),通过使用缓存技术来缓存编译的字节码,从而减轻了上述问题。

The JIT compiler reads the bytecodes in many sections (or in full, rarely) and compiles them dynamically into machine code so the program can run faster. This can be done per-file, per-function or even on any arbitrary code fragment; the code can be compiled when it is about to be executed (hence the name"just-in-time"), and then cached and reused later without needing to be recompiled.


是的,翻译语言很慢…

但是,请考虑以下内容。我有个问题要解决。我用了4分钟的时间解决了Python中的问题,程序运行花费了0.15秒。然后我试着用C语言写,我得到了0.12秒的运行时间,我花了1个小时来写。所有这些都是因为解决问题的实际方法是使用哈希表,而哈希表无论如何都控制着运行时。


因为同样的原因,通过翻译交谈要比用母语慢。或者,用字典阅读。翻译需要时间。

更新:不,在某种程度上,我没有看到我的答案与接受的答案相同;-)


阅读解释语言的利弊

这是你问题的相关观点。

An execution by an interpreter is
usually much less efficient then
regular program execution. It happens
because either every instruction
should pass an interpretation at
runtime or as in newer
implementations, the code has to be
compiled to an intermediate
representation before every execution.


现在很少有现代的脚本语言被"解释";它们通常是动态编译的,要么被编译成机器代码,要么被编译成一些中间字节码语言,这些语言在虚拟机中执行(效率更高)。

尽管如此,它们的速度会变慢,因为您的CPU对"代码行"执行了更多的指令,因为许多指令都花在了理解代码上,而不是做任何行的语义建议!


解释语言需要在执行时读取和解释源代码。对于已编译的代码,很多解释都是提前完成的(在编译时)。


来自about.com:

An Interpreted language is processed
at runtime. Every line is read,
analysed, and executed. Having to
reprocess a line every time in a loop
is what makes interpreted languages so
slow. This overhead means that
interpreted code runs between 5 - 10
times slower than compiled code. The
interpreted languages like Basic or
JavaScript are the slowest. Their
advantage is not needing to be
recompiled after changes and that is
handy when you're learning to program.

然而,对于像Java和C语言这样的语言来说,5到10倍的速度并不一定是正确的。它们是被解释的,但实时编译器可以为某些操作生成机器语言指令,从而大大加快了速度(有时接近编译语言的速度)。