为什么计算机语言会有性能的差异?

2016-01-06 16:29:43 +08:00
 temberature
8961 次点击
所在节点    程序员
86 条回复
codesun
2016-01-07 14:53:42 +08:00
编译器本质是一种映射程序,编译器从其提供的语法映射到 IR , IR 经过优化可导出汇编或直接经由 codegen 生成本地代码。

先不说别的,虽然二进制只有 0 和 1 ,但是组合爆炸,其次语言的语法不同,生成的下层表示也不同,编译器的处理方式不同,下层的代码也不同,还有最重要的优化器。

一般来说,静态编译语言速度优于解析型,即使后者有 JIT ,也很难超越前者,当然除非前者没有优化器,而且 codegen 很烂,那就另当别论了。

同样是编译型,内部也相差很大,主要取决于语言是不是提供了很多语法糖,是不是由编译器添加了比较多的隐式操作,比如运行时类型检查,运行时数组越界检查,甚至是 GC 等。这些都是开销,比如 C++编译器就会做很多这方面的工作,如 virtual 函数,多态的 vtable ,异常调用等。

对于是否有足够优秀的优化器,这里的内容相当多且复杂,就比如你的编译器支持循环的向量化优化,那么同样的程序,性能就完全不一样了。当然还有很多函数内以函数间的分析与优化,都会对性能产生不同的影响,这方面可以对比 llvm 与 gcc 。

对于编译型语言和解析型语言,差别在于前者生成本地代码,而后者生成解析器可以识别的代码,因此这里涉及从目标代码到本地代码转换的过程,你可以简单地认为解析器就是一个 while+switch 。可能看似性能差别应该不大,但是结果往往是相差一个数量级左右,看你实现地好坏了,或许直接用汇编写个解析器,性能会更好点,应该很少有人会这么做,因为现在大家完全可以用即时编译来弥补一定的性能差距。
cutepig49
2016-01-07 17:28:33 +08:00
如果完全做的是同一件事,那么结果当然应该是完全相同。
问题是在于,不同的编程语言里,看似一样的操作,其实所做的并不是同一件事。有的会添加数组越界检查,有的有 GC ,还有的数字类型天然与大数字无缝转换。
这些都与最单纯的 C 做的不是同一件事,并且这些多出来的工作代价还都不小。
Alphabetcn
2016-01-07 17:54:24 +08:00
任何事情都是要代价的,而且代价不是恒定的,更何况途径方式不一样
davidjqq19
2016-01-07 18:01:04 +08:00
@airqj 这个比喻好,有的是隔着 T 恤挠,有的是隔着棉衣,有的是隔着很多层棉衣。
wizardforcel
2016-01-07 21:23:36 +08:00
首先就是编译或者解释的执行方式。解释里面有带 jit 和不带 jit 的,又不一样。编译里面有用 gc 的,有不用 gc 而用 arc 的,有完全是手动管理内存的。然后生成的机器码长短也不一样,我不知道你玩过反汇编没有, vb6 的机器码就很长很长, c++好点,但是编译器插了很多构造析构的指令, c 算是可以一一对应上的。各种情况很复杂很复杂。
BeanMrx
2016-01-09 08:07:12 +08:00
@temberature 如果这个解释器,编译器翻译足牛的确没差异!但是实际这个问题是,语言的易用性,编译器可实现性,硬件的优化限制之间的均衡!明显的例子 C 可以指定哪个分支可能性更大辅导 CPU 指令预测,但这个增加了使用者负担,所以 Java 没有这个语义了,那么 CPU 就按照指令返回跳转认为是循环预取循环体,向下跳转预取第一分支,预测错了就要冲刷流水线!这种台相关的例子不

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/248811

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX