cpythonvm是否为每个操作码执行一个C代码?

cpythonvm是否为每个操作码执行一个C代码?,python,python-internals,Python,Python Internals,我读到一些虚拟机将字节码转换成机器码。但我听说cpythonvm略有不同。我读到PythonVM“执行一小段与操作码匹配的C代码”这是否意味着当一个Cpython解释器“执行”一个python字节码时,它最终(经过大量工作)调用不同的C程序,而这些程序又由处理器执行?如果我的理解有误,请纠正。不,它不会调用不同的程序。CPython是一个C程序。对于每个操作码,它调用自己的一个函数。这些函数本身已经编译成机器代码,因为解释器是一个编译程序 CPython不将操作码转换为机器码,这仅仅意味着它缺少

我读到一些虚拟机将字节码转换成机器码。但我听说cpythonvm略有不同。我读到PythonVM“执行一小段与操作码匹配的C代码”这是否意味着当一个Cpython解释器“执行”一个python字节码时,它最终(经过大量工作)调用不同的C程序,而这些程序又由处理器执行?如果我的理解有误,请纠正。

不,它不会调用不同的程序。CPython是一个C程序。对于每个操作码,它调用自己的一个函数。这些函数本身已经编译成机器代码,因为解释器是一个编译程序

CPython不将操作码转换为机器码,这仅仅意味着它缺少转换为本机代码的代码,例如(JIT)或提前编译程序


编译器将一组操作码转换为机器码,然后您可以直接在CPU上执行。相反,CPython一次读取一个操作码并对其作出反应。

不,它不会调用不同的程序。CPython是一个C程序。对于每个操作码,它调用自己的一个函数。这些函数本身已经编译成机器代码,因为解释器是一个编译程序

CPython不将操作码转换为机器码,这仅仅意味着它缺少转换为本机代码的代码,例如(JIT)或提前编译程序

编译器将一组操作码转换为机器码,然后您可以直接在CPU上执行。CPython解释器是一个程序(用C编写,编译成机器代码),执行Python字节码。解释器本质上是一个非常大的switch语句,它对每个不同的操作码执行不同的操作。你可以看到它是如何工作的

例如,为
二进制添加
操作码(例如
a+b
)运行的代码如下:

TARGET(BINARY_ADD) {
    PyObject *right = POP();
    PyObject *left = TOP();
    PyObject *sum;
    if (PyUnicode_CheckExact(left) &&
             PyUnicode_CheckExact(right)) {
        sum = unicode_concatenate(left, right, f, next_instr);
        /* unicode_concatenate consumed the ref to v */
    }
    else {
        sum = PyNumber_Add(left, right);
        Py_DECREF(left);
    }
    Py_DECREF(right);
    SET_TOP(sum);
    if (sum == NULL)
        goto error;
    DISPATCH();
}
请注意,这使用了许多预处理器函数来提高可读写性。在本例中,它基本上从堆栈中弹出两个对象,检查它们是否为字符串,否则调用CAPI函数
PyNumber\u Add
,该函数随后调用对象的底层
\uuuuuuuuuuuuuuuuuu Add
radd\uuuuuuuuuu
函数。然后将结果推送到堆栈。

CPython解释器是一个程序(用C编写,编译成机器代码),正在执行Python字节码。解释器本质上是一个非常大的switch语句,它对每个不同的操作码执行不同的操作。你可以看到它是如何工作的

例如,为
二进制添加
操作码(例如
a+b
)运行的代码如下:

TARGET(BINARY_ADD) {
    PyObject *right = POP();
    PyObject *left = TOP();
    PyObject *sum;
    if (PyUnicode_CheckExact(left) &&
             PyUnicode_CheckExact(right)) {
        sum = unicode_concatenate(left, right, f, next_instr);
        /* unicode_concatenate consumed the ref to v */
    }
    else {
        sum = PyNumber_Add(left, right);
        Py_DECREF(left);
    }
    Py_DECREF(right);
    SET_TOP(sum);
    if (sum == NULL)
        goto error;
    DISPATCH();
}

请注意,这使用了许多预处理器函数来提高可读写性。在本例中,它基本上从堆栈中弹出两个对象,检查它们是否为字符串,否则调用CAPI函数
PyNumber\u Add
,该函数随后调用对象的底层
\uuuuuuuuuuuuuuuuuu Add
radd\uuuuuuuuuu
函数。然后将结果推送到堆栈。

最简单的方法是,它调用不同的C函数,这些函数依次由处理器执行。事实上,最初的引文指出VM执行与操作码匹配的一小段C代码是非常正确的。最简单的方法是,它调用不同的C函数,这些函数依次由处理器执行。事实上,最初的引文指出VM执行一小段与操作码匹配的C代码是非常正确的。请注意,将操作码转换为机器码并不意味着JIT,同样的操作也可以由诸如Cython之类的提前编译器来完成。JIT确实允许通过在运行时检查使用模式进行更积极的优化。我仍然希望这有助于澄清更大的问题:编译器和解释器之间的区别。当然,总有改进的余地。:)例如,第二段可以提到“本机代码的编译器”。术语JIT定义了编译器何时运行,而不是它的输出是什么——我们不要将两者混为一谈,这会增加混乱。请注意,将操作码转换为机器码并不意味着JIT,同样的事情也可以由提前编译的编译器(如Cython)来完成。JIT确实允许通过在运行时检查使用模式进行更积极的优化。我仍然希望这有助于澄清更大的问题:编译器和解释器之间的区别。当然,总有改进的余地。:)例如,第二段可以提到“本机代码的编译器”。JIT这个术语定义了编译器何时运行,而不是它的输出是什么——我们不要将两者混为一谈,从而增加混淆。