解释型语言:级别越高越快速?

20

到目前为止,我已经设计了大约5种实验性语言及其解释器,用于教育、作为业余爱好和娱乐。

我注意到一件事:仅包含子例程和条件跳转结构的类汇编语言比包含if、while等高级结构的高级语言要慢得多。我同时开发了它们两个,都是解释型语言。我用C++编写了解释器,并尝试将代码执行部分优化为最快。

我的假设:几乎在所有情况下,解释型语言的性能随着它们的级别(高/低)而提高。

  • 我的观点基本正确吗?(如果不是,为什么?)

编辑:我在这里甚至没有一次提到“编译”,这是关于解释型与解释型的比较!


13
天啊,这里有这么多人不看问题吗?唉。OP并没有将解释型语言与编译型语言进行比较。OP正在比较高级解释型语言和低级解释型语言... - Brian Postow
2
@Brian:正如下面的讨论所证明的那样,编译和解释之间的区别似乎并不像乍一看那么清晰。 - Robert Harvey
1
@Brian,汇编语言也是一种解释性语言,它的解释器是存储在CPU中的程序。 - P Shved
2
@Brian:Java被翻译成一种中间语言,该语言会被即时编译成目标计算机的机器语言。 - Robert Harvey
1
@Pavel:我想你可以这样看待它,但那不是该术语的常用法。 - Robert Harvey
显示剩余6条评论
9个回答

30

在这两种情况下,您都需要解释代码。我想,在高级语言中,您需要更少的指令来完成相同的任务,因此您会花费更少的时间解释指令并且可以更多地做有用的事情。


1
我建议OP解释他的高级语言和低级语言之一的个人资料。如果这是原因(很可能),它应该清楚地显示在个人资料中。 - R. Martinho Fernandes
@Martinho: 我可以通过单步执行解释器来达到同样的效果。我可以通过我的疲劳程度了解它在浪费多少时间。 - Mike Dunlavey
@Mike:那正是我说的。你只是拿了一台需要蹬动的分析器:P - R. Martinho Fernandes
如果他认真努力优化解释器的主循环,他可能会发现这个差距缩小了一些。当我尝试设计语言时,谷歌“流水线解释器”让我忙碌了数周。 - Jason
@Martinho:别让我开始;-) 大多数那些用气体的探测器都错过了重点。 - Mike Dunlavey

13

最终,在您的语言中解析一行文本需要的时间大致相同,无论我们讨论汇编语言还是下一代语言(TNBL)。这在字面上并不是真的,但在图灵式的大O符号表示法下是真的。

如果确定这意味着需要(再次,“大致”)相同的时间:

mov $3, $4, $5

像这样:

print "foo"

如果我们想象用两种语言写一个Hello World程序,那么汇编解释器将不得不解析一个更复杂的程序。比如说,有n行代码,这意味着与TNBL Hello World相比,基本开销增加了n倍。

此外,你还需要在简单语言中执行所有模拟寄存器、操作等行为的代码。这是一项很大的工作。在TNBL中,解释码和宿主语言之间几乎是一对一的映射。这意味着从语义到执行的开销大大降低。

我相信你会看到一些Java程序员对这个论点提出异议,但我要指出,Java具有一些优势:一种中间字节码,试图在执行代码之前将代码尽可能接近硬件,并且投入了成千上万的人年来开发该语言的编译时和运行时优化。它们与一门业余语言完全不同。=]


4
当然,实际情况比这更加复杂。随着语言、解释器和编译器变得更加精密,机器优化性能的新机会也随之出现。此外,任何给定程序的性能取决于程序员编写代码的质量。同时,不同类型的程序受性能影响的方式也不同。例如,业务应用程序几乎总是最耗时的是从数据库中查找数据并将其发送到网络,而游戏程序员必须处理完全不同的性能概念,即视频卡帧率。因此,性能图像并不像看起来那么简单。

2
值得注意的是,他说的是他的高级解释语言比他的低级解释语言更快,而不是比编译代码更快。虽然你提出的观点完全正确,但我不认为这是他的意思。 - Adam Robinson
1
@Robert,虽然它不是汇编语言(并且编译后的代码会被缓存),但 IL 是一种解释性的低级语言 ;) - Adam Robinson
1
@Robert:每种解释型语言在某种意义上都是编译的,因为它们都必须在某个层面上转换为机器指令。唯一的区别是,IL代码的编译版本在编译后会被缓存。 - Adam Robinson
1
@Ben:这基本上就是我在我的答案中所说的。 - Robert Harvey
1
@Adam:如果在运行时,实际执行的代码不是目标代码形式,并且由虚拟机读取每个命令并即时处理,则它被解释执行。如果在运行之前,即时编译器将其转换为目标代码,则它被编译。 - Jimmeh
显示剩余9条评论

2
我认为你的看法有一半是正确的。如果你将解释速度作为纵轴,语言水平作为横轴进行绘图,你会得到一个“浴缸”曲线——对于极低水平的语言,解释速度可能很快,对于极高水平的语言,解释速度也可能很快。而在这两者之间,解释速度会明显变慢。
当输入语言非常高级(比如 APL)时,由于可以基于相对较少的输入代码进行大量工作,因此解释开销最小。
在另一个极端,你可以获得相当不错的速度,因为对于足够低级别的语言来说,解释几乎是微不足道的。Forth 实现的内部解释器就是一个很好的例子。这些实现通常以相当紧凑的方式表示给定程序,这往往非常适合缓存,并且至少在理论上,你可以获得与纯机器码相同甚至更快的执行速度。
最初的想法是,大多数 JVM、.NET“托管”环境、Smalltalk 字节码解释器等都属于后一种情况。但是,尝试开发这些环境的人很快就发现,要使解释开销足够小以实现这一点是非常困难的。我所知道的所有符合这一类别的解释器都由一个优秀的汇编语言程序员手写内部循环的汇编代码。我几乎可以说,如果你尝试使用更高级别的语言(即使是 C),它的速度会更慢,而且可能会明显地更慢(因为对于每个输入指令都增加了开销,即使在内部循环中增加一个额外的指令也几乎肯定会导致可测量的速度惩罚)。

1

显然,这将取决于您如何实现不同的语言。

我猜想,在低级别解释语言中执行相同操作需要解释更多指令,并且必须解释每个低级别指令而不是较少的高级语句,因此会有开销。


1
如果你有一种解释性语言,只需要一个命令:runMyEntireProgramNatively(),那么它比有更多命令的解释性语言更快。每个命令所做的越少,解释所花费的时间与实际执行任务的时间之比就越大。

0

摘要:基准测试很难。你不能从个别案例中得出概括性结论。

这不是有证据支持的规则。

你如何设置实验,从中得出“更高=更快”的结论?你是否有相同算法和测试集的示例实现,可以客观地衡量一种解释语言与另一种解释语言之间的差异?

如果你只是创建小型基准测试,那么你从太少的数据点中得出结论的概率非常高。

例如,如果一种解释语言具有快速排序运算符,你可能会认为“啊哈!更快!”比你必须手动实现排序的语言。然而,快速排序的最坏情况性能为O(n^2)。如果我将一个最坏情况数据集的示例交给你的高级操作,不同的手动实现归并排序将击败它。


1
你仍然可以使用解释型语言进行优化。例如:IronPython、IronRuby(我相信C的实现也有它们自己的优化)。你还可以“边编译边执行”,就像JIT编译器处理Java字节码或CIL一样。 - R. Martinho Fernandes
1
这些示例被编译成字节码(并可能经过优化),然后解释执行该字节码。 - Joel
@Joel:我不明白。字节码是一种解释性语言,并且它被解释器(又名JIT编译器)进行了优化处理。此外,IronPython也受益于DLR提供的优化,如调用站点缓存。 - R. Martinho Fernandes
再次强调,他比较的不是解释型语言和编译型语言,而是高级语言解释型与低级语言解释型的区别! - Brian Postow
@Brian,你说得对。我修改了我的答案来回应你的观点。 - Bob Cross

0

如何进行公正的比较?

我假设您不计算解析速度,并且我假设您正在生成中间字节码指令集,这就是您要解释的内容。

假设您有一个“基准测试”,它是一个循环,用于对数组元素求和。如果您的高级语言具有特殊的字节码指令,以便在高级语言中,有更少的字节码需要解释,那么这就可以解释为什么它更快。


0

假设两者实现方式大致相同,低级语言未经优化,高级语言未扩展到较低级别的中间代码 - '可能'。

在这种情况下,高级语言将具有将更多编译(更快)的代码压缩到每个指令中的优势。

但实际上,低级解释语言应该能够减少每个指令的开销,并且通常更容易实现JIT编译。最终,每种语言的实现质量将决定它们如何相互比较。

我会说,实现更快的高级语言是更容易的。(根据我的有限经验)


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