为什么解释器在实践中比编译器慢?

alg*_*der 17 compiler-construction interpreter

难道他们都不得不在某个时刻转换为机器代码来执行或者我错过了更基本的东西吗?

编辑:

请考虑更复杂的解释方案,例如将代码转换为字节代码并且仅在源代码更改时重新生成字节代码,例如Python的CPython实现?我对那些逐行重新执行的古代口译员并不感兴趣....

谢谢!

Gus*_*ram 18

像C这样的编译语言通常直接编译成机器代码.运行代码时,它由CPU直接执行.

每次运行时,通常会解释像BASIC或PHP这样的完全解释语言.执行代码时,CPU执行解释器,解释器读取并执行源代码.(PHP可以归类为完全解释,因为虽然它确实使用操作码,但它们通常在执行后被丢弃.)

像Python这样的字节码解释语言是从源代码编译为由虚拟机执行的字节码.CPU运行VM,VM执行每个字节码指令.在Python中,字节码是在第一次执行代码时编译的.

在Java中,字节码在执行之前编译.Java VM还有一个称为即时编译的特殊功能.这意味着在执行期间,它可以将一些字节码编译机器代码,它可以发送到CPU直接执行.

总之,使用编译语言,CPU直接运行代码.在解释型语言中,CPU通常运行解释器或虚拟机.由于运行VM或解释器的开销,这使得解释语言通常比编译语言慢.

注意:虽然我们说的是解释和编译语言,但我们真正讨论的是语言的常用执行风格.可以编译PHP(使用HipHop),并且可以解释C(使用Parrot VM).

  • +1 表示“虽然我们谈到解释型和编译型语言,但我们真正讨论的是一种语言的通常执行风格。” (2认同)

chi*_*ill 5

好的,这里有很多不正确的帖子,时间很长的答案.

编译器基本上是清晰的 - 它将源语言的程序转换为目标语言.两种语言都可以是任何语言 - 高级语言,虚拟机字节码,机器代码.

另一方面,解释器不执行翻译,而是直接执行源语言构造规定的动作,也就是解释它.

让我们考虑add基于堆栈的机器中的假设指令,它添加堆栈的两个顶部元素并将结果推回.解释器将直接执行 "添加两个顶部元素并将结果推回",其方式类似于:

switch (op)
{

 ....

  case OP_ADD:  
    op1 = pop (stack);
    op2 = pop (stack);
    res = op1 + op2;
    push (stack, res);
    break;

...
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,对于单个addinsn时,有许多操作执行:读取和写入内存,递增和递减堆栈指针,增加操作本身的开关的开销(如果解释是实现这种方式),开销循环读取每个后续​​insn并决定如何处理它等.

如果interpeter处理AST,它可能看起来像:

swicth (op)
{
   ...
   case OP_ADD:
     op1 = tree->eval (left);
     op2 = tree->eval (right);
     return op1 + op2;
   ...
}
Run Code Online (Sandbox Code Playgroud)

同样,许多,许多insn执行add语义所需的任何内容.

  • 真正。但是,现代的VM实现不是那么简单:它可以是直接线程代码(例如,请参见OCaml字节码VM),也可以内联所有指令。但是,大多数实现仍然不会麻烦将堆栈语义转换为3地址。 (2认同)