我认为很明显,如果我们只花时间解释代码,那么编译和执行相同的代码会更快。
嗯,不(或至少“何时”)?
将源代码转换为 CPU 真正理解的东西需要工作。有两个主要考虑因素:
a) 当这项工作完成时。是否提前/在执行任何操作之前完成工作,以便在程序运行时没有人关心它;还是在每个小片段(例如源代码语句)执行之前完成;或者是其他东西?请注意,这项工作可以(并且通常是)在多个地方拆分并完成(例如,“编译和优化以提前为 VM 生成字节码,然后做更多的工作将字节码转换为 CPU在运行时理解”)。
b) 工作做得如何。转换涉及优化,有些优化相对较快(“窥视孔”),有些优化非常昂贵。例如,假设一个程序员在某处使用int foo = 4; 创建了一个全局变量,然后另一个程序员在其他地方写了return foo * 2;;因此,在优化过程中,您希望搜索数百万行代码,以希望证明全局变量永远不会被修改,因为也许您可以将return foo *2; 转换为更快的return 8;。再举一个例子,仅仅试图以最佳方式计算寄存器分配(哪些变量进入哪些寄存器)是一个已知的“NP-complete”问题。
我无法理解的是 jit 编译器如何在服务器上实现比解释语言更好的性能(通常),在服务器上有数千个连接 - 是否需要为每个连接重新编译代码
纯解释器的性能极差。每次执行每个小片段(源代码的每个语句,或者如果提前预编译的每个字节码)执行时,都会发生将代码转换为 CPU 可以理解的工作,即使这项工作已经完成以前做过数百万次;而且因为它正在处理如此微小的部分,几乎所有优化都是不可能的。
纯 JIT 性能非常差。将代码转换为 CPU 可以理解的内容所涉及的工作在第一次执行一小段(源代码的每个线性语句组,或者如果提前预编译的字节码线性组)被执行时发生,即使这项工作只需要一次;并且因为它在小块上工作,大多数优化是不可能的。
为了避免一些问题;大多数现代 VM 使用“混合解释和 JIT”方法,其中(例如)它们可能会在第一次执行代码时解释代码(以避免 JIT 的费用),但在第二次执行时切换到 JIT(假设如果某些东西是执行两次它可能会执行多次,希望避免“将代码转换为 CPU 理解数百万次(如果它最终被执行数百万次)”的问题)。不过……
“混合解释和 JIT”性能不佳。它仍然无法进行任何昂贵的优化,仍然无法在代码执行之前转换为原生一次(并避免“每次启动程序时转换”问题)等等。
本机代码编译器往往只会为您提供足够的性能。它仍然远非完美。
要了解的重要一点是性能是相对的。如果一件事的性能很差(与完美的优化器相比),而另一件事的性能很差(与完美的优化器相比);那么“坏”与“非常坏”相比是好的。通过更改参考点(例如将所有内容与药物上的猴子进行比较),您可以说提前编译为本机可以提供非常好的性能(与药物上的猴子相比),“混合解释和 JIT”可以提供非常好的性能(比较对一只吸毒的猴子),纯 JIT 提供了良好的性能(与一只吸毒的猴子相比),纯解释提供了足够的性能(与一只吸毒的猴子相比)。