Python语言的执行流程总结

本文主要总结下Python执行时的一些流程细节和疑惑环节

Python代码的执行流程

Python代码的执行流程,并非简单的"编译"或"解释"二选一,而是一个编译 + 解释的混合过程。

整个过程可以分为两大阶段:编译时运行时。下面我为你详细拆解每一个步骤。


第一阶段:编译时(从源码到字节码)

当你执行一个Python程序(例如 python main.py)时,解释器并不会直接读取并执行文本文件里的代码,而是先进行编译。

  • 词法分析与语法分析

    • 词法分析 :解释器将源代码(字符流)拆分成一个个有意义的"单词",即Token (关键字、标识符、运算符等)。例如,x = 1 会被拆分为 NAME(x)、OP(=)、NUMBER(1)。

    • 语法分析 :根据Python的语法规则,将Token序列组织成一棵抽象语法树(AST) 。这棵树描绘了代码的逻辑结构,但如果代码有语法错误(如缺少冒号),这一步就会直接抛出 SyntaxError 并终止。

  • 编译为字节码

    • Python解释器(通常指CPython)会将生成的AST编译为字节码(Bytecode)。字节码是一种低级的、与平台无关的中间表示,它比文本代码更紧凑,且执行效率更高。

    • .pyc 文件 :编译完成后,解释器通常会将字节码保存为 .pyc 文件,存放在 __pycache__ 目录下。下次再运行同一文件时,如果源代码没有修改(解释器会比对时间戳),就直接加载 .pyc 文件,跳过编译步骤,从而提升启动速度。


第二阶段:运行时(从字节码到机器码)

编译完成后,真正的执行才刚刚开始。Python的核心是一个虚拟机(PVM,Python Virtual Machine),它负责执行字节码。

  • 构建运行时环境

    • 在逐条执行字节码之前,解释器会先准备好运行时环境,这包括:

      • 创建内置模块(如 builtins)。

      • 设置 sys.path 模块搜索路径。

      • 准备 __main__ 模块的命名空间。

  • 执行核心:解释器循环(Eval Loop)

    • PVM 会进入一个巨大的 while 循环,这个循环被称为"解释器主循环"或"求值循环"。

    • 在这个循环中,它会从当前代码对象(Code Object)中逐条读取字节码指令,然后根据指令执行对应的操作。

    • 例如,字节码指令 LOAD_FAST 0(加载变量)会被解释器翻译为"从局部变量字典的索引0处取值",BINARY_OP + 会被翻译为"执行加法运算"。

  • 运行时动态特性(这是关键)

    • 与静态编译语言(如C++)不同,Python 在字节码执行期间,会动态处理:

      • 变量查找:变量名在运行时通过命名空间(字典)查找,而不是通过内存地址。

      • 类型判断 :Python 是动态类型,a + b 具体是整数加法还是字符串拼接,要等到运行时看到 ab 的实际类型才能决定。

      • 猴子补丁与动态修改:函数、类甚至模块都可以在运行时被替换,这决定了 Python 无法像 C 语言那样进行深度的提前优化(AOT)。


一个特殊机制:__pycache__ 与导入优化

  • 当你直接运行 python main.py 时,字节码通常不会 被保存(除非使用 -m 等参数),仅在内存中执行完毕即销毁。

  • 但当你导入 一个模块(如 import utils)时,Python 会主动将 utils.py 编译并保存为 utils.cpython-39.pyc。这是为了后续导入时省去编译时间,提升模块加载速度(请注意,是加载速度,而非运行速度)。


理解执行流程的实用例子

看下面这段代码:

复制代码
def add(a, b):
    return a + b

result = add(1, 2)
print(result)

执行流程如下:

  • 编译 :整个文件被编译成字节码,包含函数 add 的定义体(但此时函数体内部的 a+b不会执行)。

  • 运行时(第3行) :执行到 result = add(1, 2)

    • 解释器在全局命名空间中找到 add 这个名字。

    • 创建一个新的栈帧(Frame) ,用于管理 add 函数的局部变量(a=1, b=2)。

    • 在栈帧内部,执行 return a + b 的字节码,此时 ab 的类型被动态识别为整数,执行整数加法。

    • 计算结果 3 返回到上一层栈帧,赋值给 result

  • 运行时(第4行) :执行 print,解释器去全局查找 print 函数,调用它,结束。

编译->运行

是先全部编译完再运行,还是一遍编译一边运行?

这是一个非常经典且容易混淆的问题。答案是:先全部编译完,再运行

但在解释这个"全部"之前,需要先厘清一个关键概念:编译的单位是什么?

Python 的编译单位是整个代码文件(模块),而不是一行一行地编译。这意味着:

  1. 编译阶段 :Python 解释器会从头到尾读取整个 .py 文件,进行词法、语法分析,生成完整的字节码(.pyc 内容)。这个过程完全结束后,编译阶段才完成。

  2. 运行阶段:编译完成后,Python 虚拟机(PVM)才开始逐条执行内存中的字节码指令。


为什么直觉上感觉像是"一边编译一边运行"?

很多人产生这种错觉,是因为看到了 Python 交互式命令行(REPL)。在交互式环境中,你输入一行代码,它立刻给你结果,这看起来像一边编译一边运行。

但实际上,交互式环境是一个特例 。当你敲下回车时,REPL 会立即对当前输入的这行或这个代码块 执行完整的"编译 -> 运行"流程,然后等待你输入下一行。但对于一个标准的 .py 脚本文件,绝对是先全量编译,再全量运行。


用一个实验来"铁证如山"

我们写一个包含致命语法错误正常输出 的文件 test.py

复制代码
# 第一行:一个明显的语法错误(缺少冒号)
print("Hello")
if True
    print("World")
# 第三行:一个正常的输出
print("End")

如果你执行 python test.py,猜猜结果是什么?会不会先输出 "Hello",然后报错?

实际结果是:

复制代码
  File "D:\test.py", line 2
    if True
         ^
SyntaxError: invalid syntax

程序直接报错,没有任何输出

  • 如果是一边编译一边运行,第一行 print("Hello") 应该被编译并执行,屏幕会先打印 "Hello"。

  • 但现实是,解释器在编译阶段 扫描到第二行的语法错误后,直接抛出 SyntaxError 并终止程序。运行阶段根本没有启动,所以第一行代码虽然语法正确,但也完全没有被执行。

Python解释器和虚拟机

python解释器和虚拟机不是一个东西吗?我们在官网下载的python是啥?

这个问题问到了根子上,很多人用了很久Python都没搞清楚这里的关系。

直接回答你:在CPython(官方版本)中,解释器和虚拟机确实是"你中有我,我中有你"的同一个东西,但在概念上,它们是"外壳"和"内核"的关系。

为了让你彻底明白,我们先从概念说起,再落地到你下载的那个东西上。


第一层:概念上的区别(理论层面)

在计算机科学中,这两个词的定义是泾渭分明的:

  • 解释器(Interpreter) :是一个**"翻译官"** 。它的职责是读入源代码,并将其翻译成某种可以执行的形式。它关注的是**"输入是什么"** (源代码)和**"输出是什么"**(执行结果)。

  • 虚拟机(Virtual Machine / PVM) :是一个**"虚拟的CPU"** 。它不直接面对源代码,而是面对一种特定的中间指令(即字节码)。它关注的是**"如何执行这些指令"**(如怎么取数、怎么相加、怎么跳转)。

按照这个理论,一个完整的Python执行环境 = 解释器(编译部分) + 虚拟机(运行部分)


第二层:落地到CPython(你下载的东西)

你在官网(python.org)下载的安装包,名字通常叫 CPython

CPython 并不是一个单纯的"解释器"或"虚拟机",而是一个将这二者深度耦合在一起的完整可执行程序(python.exe)。

在这个 python.exe 内部,流程是这样的:

  1. 前端(解释器角色) :负责读取你的 .py 文件,进行词法、语法分析,生成字节码。这部分在CPython源码中通常称为 Compiler(编译器)

  2. 后端(虚拟机角色) :负责执行这些字节码。这部分在CPython源码中称为 PVM(Python Virtual Machine) ,它的核心是一个巨大的 _PyEval_EvalFrameDefault 函数(即求值循环)。

关键点来了: 在CPython的实现里,编译器和虚拟机被编译进了同一个 .exe 文件里 。当你双击运行 .py 文件时,这个进程会先调用编译器模块把代码变成字节码,然后立刻把控制权移交给虚拟机模块去跑。

所以,当Python程序员说"Python解释器"时,通常泛指整个 python.exe 这个应用程序;当他说"Python虚拟机"时,通常特指里面那个执行字节码的引擎。


第三层:为什么官方不把它们拆开卖?

你可能会问:既然概念上分开,为什么官方不提供一个单独的 compiler.exevm.exe

因为Python是动态语言 ,编译器和虚拟机在运行时需要频繁交互。举个最典型的例子:

复制代码
a = 1
b = "2"
print(a + b)
  • 编译器在编译时,只知道这里有加法,但它不知道 a 是整数、b 是字符串(因为类型是运行时才确定的)。

  • 当虚拟机执行到加法指令时,发现类型不匹配(int + str),它会抛出 TypeError

如果编译器和虚拟机是分开的两个独立程序,那么虚拟机在执行报错时,还得跨进程去通知编译器,效率极低。正是因为它们在同一个进程里(同一个 .exe),虚拟机才能随时调用编译时生成的符号表和上下文信息,实现动态特性。


第四层:对其他Python实现的补充

理解了CPython,再看看其他实现,你就更清楚了:

实现名称 解释器/编译器 虚拟机 说明
CPython 内置(C语言编写) PVM(C语言编写) 你下载的就是这个,二者合体。
PyPy 内置(Python编写) JIT虚拟机 它把编译器和虚拟机也合在一起,但虚拟机里加入了即时编译技术,能把热点字节码转成机器码。
Jython 内置 JVM(Java虚拟机) 它的编译器把Python代码编译成Java字节码,然后扔给 外部的 JVM去运行。此时解释器(前端)和虚拟机(JVM)就是两个独立的程序了。
IronPython 内置 CLR(.NET公共语言运行时) 类似Jython,借用外部的.NET虚拟机。

最后,回答你下载的那个"Python"到底是什么

你在官网下载的 python-3.x.x-amd64.exe 安装完成后,你的电脑里就有了:

  1. 解释器核心 (能把 .py 变成 .pyc 字节码的编译器)。

  2. 虚拟机核心 (能把 .pyc 跑起来的PVM循环)。

  3. 标准库 (成千上万个预先写好的 .py 模块,如 ossysjson)。

  4. 交互式环境(REPL)(让你敲一行跑一行的那个界面)。

它本质上是一个名为"CPython"的完整运行时环境。我们平时口语中说"装了个Python",其实指的是"装了一个名为CPython的、包含编译器和虚拟机的应用程序套件"。

是否需要编译链接是从上层开发者角度来看的

为啥都是编程语言,有的需要编译链接,有的不需要?

核心根源:语言设计目标不同,目标机器不一样

  • C/C++ 目标:直接跑在CPU 硬件
  • Python/Shell 目标:跑在软件解释器 / 虚拟机

CPU 只能看懂 0 和 1 的机器码,看不懂人类写的源代码。所有编程语言,最终都要变成机器码才能跑,区别只在于:这件事是谁来干、什么时候干、要不要你手动操作

一、C 语言:编译 + 链接,直接面向 CPU

C 的设计初衷:写操作系统、驱动,直接跟硬件打交道,追求极致速度

CPU 不认 C 源码,所以要两步:

  1. 编译 :把.c源码翻译成 CPU 看得懂的机器码,产出目标文件.o
  2. 链接:你的代码要调用系统库函数(printf、malloc),链接器把你的机器码 + 系统库的机器码拼到一块,合成一个完整可执行文件(Windows exe、Linux elf)。

👉 结果:得到一个独立二进制程序,脱离编译器直接交给 CPU 运行

代价:你必须手动执行 gcc 编译、链接;改代码就要重新编译链接。

复制代码
人类写C源码 →【你调用编译器编译】→目标文件 →【你调用链接器】→独立可执行程序 → CPU直接执行

二、Python:不用你编译链接,多了一层虚拟机

Python 不想让你操作复杂编译链接,它加了一层Python 虚拟机(PVM,一个软件程序)

CPU 看不懂 Python 源码,但CPU 可以运行 Python 解释器这个软件。流程:

  1. 运行python test.py,解释器启动;
  2. 内部自动把源码编译成字节码(不是 CPU 机器码!是给 Python 虚拟机看的指令);
  3. Python 虚拟机软件读取字节码,翻译成真正 CPU 机器码,交给 CPU 执行。

关键点:

  1. 编译是程序内部偷偷做的,不用你敲命令

  2. 完全没有链接步骤:库导入是运行时虚拟机动态加载,不是链接阶段把二进制拼进去;

  3. 字节码只能给 Python 虚拟机识别,不能直接给 CPU 跑。

    人类写Python源码 →【解释器内部自动编译成字节码】→ Python虚拟机 →转成机器码→ CPU执行

pyc 就是缓存的字节码,只是省去下次重复编译源码,依然需要虚拟机。

三、Shell/bash:纯解释,连内部编译都几乎没有

Shell 的定位:调用系统命令,做脚本自动化,简单胶水语言。bash 解释器拿到脚本,读一行,解析一行,执行一行,不会生成任何中间字节码文件。

复制代码
Shell源码 → bash解释器逐行解析 →调用系统接口 →CPU执行

一张通俗对比

语言 最终给谁执行 是否要你手动编译链接 中间产物
C/C++ 直接 CPU ✅要编译 + 链接 exe/elf 二进制
Python Python 虚拟机软件 ❌不用(内部自动编译字节码) pyc 字节码文件
Bash Shell bash 解释器软件 ❌完全不用 无中间文件

链接到底是干嘛的?为什么脚本语言不需要链接?

链接本质:构建独立完整的二进制可执行文件,把所有用到的库的机器码提前合并到程序里

  • C:编译完只是你的代码片段,printf 这些函数在系统库里,链接把它们拼在一起,生成完整程序。
  • Python:不需要生成独立二进制。需要库的时候,程序跑起来之后虚拟机动态导入模块,运行时加载,不是编译阶段把二进制拼起来,所以没有链接。

为什么不全部做成脚本语言,不用编译多舒服?

凡事有取舍:

  1. ✅脚本语言好处:写好直接跑,开发快,跨平台(只要装对应解释器)
  2. ❌缺点:多一层虚拟机 / 解释器,多一层软件翻译,运行速度慢

C/C++ 编译链接虽然麻烦,但是产出的程序直接喂给 CPU,少中间层,速度极快,适合操作系统、驱动、游戏引擎。

补充:现代边界模糊

  • PyPy (JIT):运行的时候把 Python 字节码动态编译成机器码,提速。
  • Cython:把 Python 转 C 再编译。
  • Go 语言:编译成独立二进制,但是链接过程内置,一条命令完成,用户感知不到链接。

大白话总结

  1. 编译 = 翻译源码,链接 = 把零散代码和库拼装成完整程序。
  2. C 系:翻译 + 拼装交给你手动完成,产出直接给 CPU 跑的文件。
  3. Python:翻译交给解释器偷偷完成,产出给虚拟机看的字节码,库运行时加载,不用拼装链接。
  4. Shell:边读边翻译,连预翻译都不做。
  5. 没有绝对好坏:追求运行速度选编译型;追求开发简单快捷选脚本语言。

CPython

CPython是啥,它本身就是个C运行程序吧?

CPython 就是 Python 语言的官方标准实现,我们平时官网下载安装的那个 Python 就是它。

名字里的 C ,意思是:这个解释器 / 虚拟机是用 C 语言写出来的

注意区分两件东西:

  1. Python 语言:一套语法规则、规范(什么是 if、for、函数、类),只是文档标准,本身不是软件。
  2. CPython:把这套语言规范做成实实在在可运行的程序,是一个软件实现。

CPython 本质上就是一个用 C 语言编写、编译而成的原生可执行程序(在 Windows 上就是 python.exe,在 Linux 上就是 python 二进制文件)。

它和你电脑上其他 .exe 程序(比如 Chrome 浏览器、记事本)在底层没有区别,都是直接运行在操作系统和 CPU 之上的机器码。只不过,别的程序处理的是文字、图片或网络数据,而 CPython 这个程序处理的"数据"恰好是 Python 源代码文件

为了让你彻底看清它的真面目,我们可以从三个层面来拆解:

1. 从"外壳"看:它就是普通的 C 程序

当你从官网下载并安装 Python 后,你得到的 python.exe 文件,其本体就是 CPython 源代码经过 C 编译器(如 GCC 或 MSVC)编译链接后生成的。

你可以把 CPython 的源码想象成这样(极度简化版):

复制代码
// 这是 CPython 主程序的入口,相当于 C 语言的 main 函数
int main(int argc, char *argv[]) {
    // 1. 读取你传入的 .py 文件内容
    char* source_code = read_file(argv[1]);
    
    // 2. 调用词法/语法分析模块,生成字节码(编译器功能)
    PyCodeObject* code = compile(source_code);
    
    // 3. 调用虚拟机主循环,执行字节码(虚拟机功能)
    PyObject* result = PyEval_EvalCode(code);
    
    // 4. 打印结果并退出
    return 0;
}

这个程序被操作系统加载后,CPU 会逐条执行这些 C 语言编译后的机器指令。它并没有"魔法",只是一个专门用来"吃掉 Python 代码,吐出执行结果"的普通进程。


2. 从"内部"看:它内置了 Python 的"运行时工厂"

既然它是个 C 程序,那为什么能跑 Python 代码呢?因为在它的内存空间里,CPython 维护了一套庞大的 C 语言结构体(Struct)指针,用来模拟 Python 的世界。

  • PyObject(Python 对象) :你在 Python 里写的 a = 1,在 CPython 内存中,就是一个 C 结构体 struct PyLongObject,里面包含了数值 1 和引用计数。

  • PyFrameObject(栈帧):当你调用函数时,CPython 会在堆内存中创建一个 C 结构体来管理局部变量、指令指针等。

  • PyDictObject(字典) :你用的 dict,底层就是一个 C 语言实现的哈希表。

CPython 这个 C 程序,在运行期间不断地 malloc(申请内存)和 free(释放内存),动态地构建出 Python 代码中定义的各种对象。 可以说,它是一个用 C 写成的"Python 世界模拟器"。


3. 为什么叫 "C" Python?

因为它几乎所有核心组件(编译器、虚拟机、内置数据类型)都是用 C 语言实现的 ,并且它开放了 C API(应用程序编程接口) ,允许你用 C 语言编写扩展模块(比如 numpy 中的矩阵运算底层就是 C 写的),然后让 Python 调用。

与之对比:

  • PyPy :是用 Python 语言本身(确切地说是 RPython 子集)写成的 Python 实现。它的可执行程序底层不是纯 C,而是包含了一个 JIT(即时编译器)。

  • Jython :是用 Java 语言写成的 Python 实现,它跑在 JVM(Java虚拟机)上。


为了印证这一点,做个"灵魂拷问"

如果你的电脑上没有任何 C 语言运行时(比如 msvcp140.dll)会怎样?在 Windows 上安装 Python 时,安装包往往会顺带安装 Microsoft Visual C++ Redistributable

这是因为 CPython 的源码编译后,动态链接到了 Windows 的 C 标准库。这铁证如山:CPython 就是一个依赖 C 库才能跑起来的原生 C 程序。

Python具体慢在哪

Python执行慢,到底是哪些环节慢?

这个问题问得非常专业。既然你已经理解了CPython是C程序、且流程分为"编译"和"运行",那我们就可以抛开"Python慢"这种笼统的说法,把手术刀切到具体的环节上

结论先抛出来:Python 慢,90%以上的锅在"运行时(虚拟机执行字节码)"环节,而不是编译环节。 编译虽然慢一点,但在整个执行周期中占比极小。

下面我把整个流程拆开,给你看看到底是哪些具体动作在拖慢速度。


第一环节:编译阶段(几乎不慢,可以忽略)

  • 做什么 :把 .py 文本变成 .pyc 字节码(词法分析、语法分析、生成AST、生成Code Object)。

  • 速度非常快 。因为Python语法相对简单,没有像C++那样复杂的模板实例化或宏展开。一个10万行的项目,编译耗时通常在 毫秒到几十毫秒 级别。

  • 结论启动时稍微有点慢(因为要扫描文件),但运行时完全不受影响。 这也是为什么 .pyc 文件只能加速启动,不能加速运行的原因。


第二环节:运行时(慢性子的大本营)

这是Python变慢的核心地带。当虚拟机(PVM)进入主循环,逐条执行字节码时,噩梦开始了。

1. 动态类型检查(最致命的瓶颈)

这是Python慢的头号元凶 。看这行代码:a + b

  • 在C语言中:编译时已经确定 ab 都是 int,CPU一条 ADD 指令(纳秒级)直接搞定。

  • 在Python中:虚拟机看到 BINARY_OP + 指令后,必须执行以下C函数调用链:

    1. 获取 a 的对象指针。

    2. 查看 aob_type(类型字段),确认它是整数还是字符串还是列表?

    3. 根据类型,去 a 的类型对象里查找 __add__ 方法的函数指针。

    4. 调用该C函数,将 b 作为参数传进去。

    5. 在该C函数内部,还要再次检查 b 的类型是否匹配。

    6. 创建一个新的 PyLongObject 对象来存放结果(涉及内存分配)。

这一整套流程下来,少说几百纳秒,多则几微秒。而CPU原生的整数加法只需不到1纳秒。Python在这里慢了 100倍以上

2. 频繁的内存分配与GC(垃圾回收)压力

在Python中,万物皆对象。这意味着:

  • 你写 x = 1,不是在栈上分配一个4字节的整数,而是在堆上 malloc 一个28字节的 PyLongObject 结构体。

  • 你写 a = [1,2,3],列表里的每个元素都是指向独立对象的指针。

  • 循环一万次 i += 1,意味着创建了一万个新的整数对象(因为整数不可变),旧的被丢弃,触发内存管理器的频繁回收。

C语言在做同样的事情时,可能只是在修改一块已有的内存地址。而Python在不停地申请、赋值、释放、引用计数加减。 这种内存体操极大地拖慢了速度。

3. 解释器开销(字节码分发)

虚拟机内部是一个巨大的 switchgoto 循环(_PyEval_EvalFrameDefault)。

  • 执行 LOAD_FAST(加载变量)、STORE_FAST(存储变量)这些简单指令时,虽然底层是C语言,但每次读取下一条指令、解析操作数、跳转到对应的处理逻辑,本身就有固定的循环开销。

  • 一条Python字节码对应几十条C机器码。而同样的逻辑如果用C写,直接就是几条机器码。这中间有 10倍左右的常数开销

4. GIL(全局解释器锁)带来的副作用

虽然GIL主要是影响多线程并行,但它也会影响单线程的执行效率。因为GIL的存在,CPython无法利用多核CPU进行指令级并行优化(如超标量流水线),并且每次执行字节码时都需要频繁地获取和释放这把巨锁,增加了额外的上下文切换成本。


来做个直观的对比实验

用同样的逻辑,分别用Python和C实现一个空循环100万次:

Python代码:

复制代码
i = 0
while i < 1000000:
    i += 1

耗时 :约 0.05秒(Python 3.11+)

C语言代码:

复制代码
int i = 0;
while (i < 1000000) i++;

耗时 :约 0.001秒(优化后甚至会被编译器直接优化掉)

慢了50倍。 这50倍,全耗在了刚才说的"动态类型检查"、"整数对象创建/销毁"、"循环字节码分发"这三个环节上。


哪个环节不慢?(出乎意料)

  • I/O操作(读写文件、网络请求)不慢 :因为Python的 socketfile 底层调用的C库(read()write()),在等待操作系统响应时,Python的虚拟机处于阻塞状态,这部分时间开销和语言无关。

  • 内置函数(sum()sort()list.append())不慢 :因为这些函数的循环逻辑是在C语言层面执行的,避开了Python字节码的解释开销。所以写Python代码时,能用内置函数就别用 for 循环


一张表总结慢在哪里

执行环节 速度级别 主要原因 是否背锅
编译(.py -> .pyc) 毫秒级 字符串处理、建树 不背锅(占比<1%)
变量/属性查找 字典哈希查找(dict 查询) 背大锅
算术运算/逻辑操作 极慢 动态类型判断 + 对象内存分配 背最大的锅
循环迭代 每次都要调用迭代器的 __next__ 背大锅
函数调用 较慢 创建栈帧(Frame)、压栈弹栈 背中锅
C扩展库调用(如Numpy) 绕过虚拟机,直接跑C机器码 不背锅

延伸思考:既然这么慢,为什么还能用?

因为现代计算机CPU太快了,对于Web后端、脚本自动化这些I/O密集型 任务,Python的慢(微秒级)根本比不上网络延迟(毫秒级)。只有在CPU密集型 计算(如大循环、图像处理)时,才会感受到明显的卡顿------而这时人们通常会用 numpy(C写的)或 Numba(JIT编译)来绕过虚拟机。

------------------------"总的来说,就是逐条解析字节码的过程慢"

CPython(纯解释型)------ 软件模拟

  • 执行方式 :源代码 -> 字节码 -> 永远由虚拟机(C程序)逐条读取并分发执行

  • CPU视角 :CPU老老实实地执行 python.exe 这个C程序的机器码。在这个C程序里,有一个巨大的 switch 语句(或者 goto 跳转表)。每执行一条Python字节码,CPU就要跑一遍"从内存读字节码 -> 解析操作码 -> 跳转到对应的C函数 -> 执行C函数 -> 返回循环头"的固定流程。

  • 速度通常比基准慢 10倍 ~ 100倍

相关推荐
民乐团扒谱机2 小时前
【超详解】量子克拉美罗下界QCRB:时延估计精度极限推导+MATLAB多场景绘图实战
开发语言·机器学习·matlab·量子力学·qcrb
宋均浩2 小时前
AI 生成代码质量防线实战:5 个 CI/CD 配置,把 8% 的逻辑错拦在线上之前0
python
树码小子2 小时前
Pycharm解释器配置问题解决
ide·python·pycharm
国雪2 小时前
python-协程
python
乐观勇敢坚强的老彭2 小时前
C++ 竞赛常用算法模板速查表
开发语言·c++·算法
一木 之林3 小时前
Python.六.(一)--1.标准库、常用工具与基础操作(进阶)
python·rpc·dubbo
离陌在学C#3 小时前
C# 泛型:从基础到高级应用
开发语言·c#
ly76893 小时前
Java 设计模式详解:从原则到 23 种经典模式
java·开发语言·设计模式
SomeB1oody3 小时前
【RustyML入门】2.13. 孤立森林
开发语言·后端·机器学习·rust·教程