在了解 Python 协程的实现原理的时候,对于几种语言的运行机制有了更进一步的认识。本文简单记录一下集中常见语言的运行机制,可以更好的理解比较。
首先明确一下几种语言类型,以 C/C++,Java,Python 和 Node.js 为例,它们的运行机制可以简单概括如下:
C/C++ 是直接通过编译器(如 GCC、Clang)转换为目标机器的二进制机器码,编译直接生成针对底层硬件生成的高效的 二进制机器码可执行文件,可以直接由操作系统运行。
Java 是先将代码编译为字节码,然后在 真正运行时通过 JVM 解释字节码执行,各个平台有自己的 JVM 实现,所以字节码可以跨平台运行。在配合 JIT 编译以后,JVM 可以将热点代码编译为机器码,提高执行效率,在许多场景下与 C/C++ 的性能差距已经非常小了。
Python 是一种解释型语言,以 CPython 为例,其解析器、编译器和虚拟机都是用 C 语言实现的,Python 代码在运行时会先经过解释器解析为抽象语法树(AST),然后编译为字节码(.pyc
文件),最后由 Python 虚拟机(PVM)逐条执行字节码,这种解释执行的方式导致 Python 的运行效率相对较低。虽然 Python 本身运行效率较低,但 CPython 可以通过 C 扩展库(如 NumPy、TensorFlow)调用高效的底层实现,大幅提升性能,这种机制被称为 Python C API,这使得 Python 尽管速度慢,但在数据科学和机器学习领域仍然非常强大。
C 扩展模块是共享库,编译后是
.so
(Linux/macOS)或.dll
(Windows)格式的共享库,CPython 可以直接加载这些共享库,并通过 C API 调用其中的函数。
NumPy 的底层核心部分是用 C 语言实现的(比如数组操作和矩阵计算)。NumPy 通过调用高性能的 BLAS 和 LAPACK 库(用 C 或 Fortran 实现的数值计算库)来提升性能。
Node.js 是基于 Google V8 引擎的 JavaScript 运行时环境,它直接加载和运行 JavaScript 源代码,其底层运行方式结合了解释和即时编译(JIT)技术,所以它介于解释型语言和编译型语言之间。
在 V8 引擎中,JavaScript 代码首先被解析为抽象语法树(AST),然后通过解释器(Ignition)将代码转换为字节码并执行,同时 JIT 编译器(TurboFan)会动态分析运行时的热点代码,将热点字节码优化为机器码,在 CPU 上直接运行以进一步提升性能。Node.js 的事件驱动模型和非阻塞 I/O 由 libuv 提供支持,主线程通过事件循环调度任务,I/O 操作交给线程池或操作系统异步处理,从而避免阻塞,适合处理高并发的 I/O 密集型任务,如 Web 服务器、聊天应用、API 网关和实时流媒体服务。
上面多次提到了虚拟机的概念,在编程语言的语境中,虚拟机(Virtual Machine, VM) 是一个更广义的概念,指的是一种 在抽象层上模拟计算机硬件或软件运行环境的程序。
CPython 的虚拟机扮演了解释器、栈操作、异常处理和上下文管理等角色,下面简单介绍一下 CPython 的虚拟机:
CPython 的虚拟机首先是一个解释器,用来逐条解释 Python 的字节码指令。字节码是一组简单的、与平台无关的操作码,例如:
x = 1 + 2
编译成的字节码可能是这样的:
LOAD_CONST 1 LOAD_CONST 2 BINARY_ADD STORE_NAME x
虚拟机会逐条执行这些指令,并在内部用 C 语言实现的操作完成任务。
虚拟机通过一个栈结构来管理字节码的执行。比如上例中,BINARY_ADD
会从栈中弹出两个值(1
和 2
),执行加法操作后将结果(3
)压回栈中。
虚拟机负责处理 Python 的异常机制和上下文管理(如 try...except
、with
)。这些逻辑直接在 C 语言中实现。
下面以 Python 为例,简单分析一下 Python 代码的执行流程,假设有如下代码:
x = 10 y = 20 z = x + y print(z)
CPython 主要有如下三步执行过程:
解析(C 语言实现的解析器):脚本被解析成抽象语法树(AST)。
编译(C 语言实现的编译器):AST 被编译成字节码:
1. LOAD_CONST 10 2. STORE_NAME x 3. LOAD_CONST 20 4. STORE_NAME y 5. LOAD_NAME x 6. LOAD_NAME y 7. BINARY_ADD 8. STORE_NAME z 9. LOAD_NAME z 10. PRINT_EXPR
执行(C 语言实现的虚拟机解释字节码):每条指令被虚拟机逐条执行:
builtin_print
。