Python 3.11.3编译版本性能低于解释版本的原因咨询
Python 3.11编译版本运行慢于解释版本的原因分析
测试背景与结果
环境信息
- Python版本:3.11.3(解释版)、3.9(编译版对比)
- 编译工具:PyInstaller 5.11.0、cx_Freeze
性能对比数据
| 测试项 | 编译版本(3.9/3.11.3) | 未编译版本(3.11.3) |
|---|---|---|
| test fib | 452.0 ms | 283.0 ms |
| test geometry | 1026.0 ms | 437.0 ms |
| test data | 54.0 ms | 30.0 ms |
测试代码
import time import math import random import hashlib import os import sys def fib(n): if(n == 0 or n == 1): return n else: return fib(n-1) + fib(n-2) def test_geometry(vector3_1, vector3_2, radius1, radius2, radius3): distance = math.sqrt((vector3_2[0] - vector3_1[0])**2 + (vector3_2[1] - vector3_1[1])**2 + (vector3_2[2] - vector3_1[2])**2) distance_between_centers = math.sqrt((vector3_2[0] - vector3_1[0])**2 + (vector3_2[1] - vector3_1[1])**2 + (vector3_2[2] - vector3_1[2])**2) sphere_volume = (4/3) * math.pi * (radius3**3) def load_data(): current_dir = os.path.dirname(sys.argv[0]) data_file_path = os.path.join(current_dir, 'data.txt') try: with open(data_file_path, "r") as f: data = f.read() return data except FileNotFoundError: print("Arquivo 'data.txt' não encontrado.") start_fib = time.time() result_fib = fib(32) finish_fib = time.time() vector3_1 = (random.uniform(1, 10), random.uniform(1, 10), random.uniform(1, 10)) vector3_2 = (random.uniform(1, 10), random.uniform(1, 10), random.uniform(1, 10)) radius1 = random.uniform(1, 10) radius2 = random.uniform(1, 10) radius3 = random.uniform(1, 10) start_geometry = time.time() for i in range(1000000): result_geometry = test_geometry(vector3_1, vector3_2, radius1, radius2, radius3) finish_geometry = time.time() start_data = time.time() load_data() finish_data = time.time() print("python:") print(f"teste fib: {round((finish_fib-start_fib)*1000, 0)} ms") print(f"teste geometry: {round((finish_geometry-start_geometry)*1000, 0)} ms") print(f"teste data: {round((finish_data-start_data)*1000, 0)} ms\n")
原因解析
1. 打包工具的本质不是“编译为原生代码”
PyInstaller和cx_Freeze只是将Python解释器、代码及依赖打包成可执行文件,并没有把Python代码编译成机器码。运行时依然依赖Python解释器执行字节码,和直接运行脚本的核心逻辑一致,但多了打包后的额外开销:
- 启动阶段需要将打包的资源解压到临时目录,加载依赖的速度慢于直接运行本地文件
- 模块加载、路径查找逻辑因打包结构变化,引入了额外的性能损耗
2. Python 3.11的字节码优化未被正确保留
Python 3.11的核心性能提升来自Faster CPython项目,通过优化字节码生成、指令集等大幅加速了解释执行。但打包工具在处理3.11代码时,可能没有正确保留这些优化特性,或是打包过程中重新生成的字节码未应用3.11的优化,导致编译包的执行效率退回到类似Python 3.9的水平。
3. 高频调用的累积开销
测试中test_geometry被循环调用100万次,打包后的可执行文件在函数调用路径上因封装逻辑多了一层间接调用,单次开销虽小,但累积后放大了性能差异。
4. 文件IO的路径解析损耗
load_data通过sys.argv[0]获取路径,打包后的可执行文件需要处理自身的封装结构或临时目录路径,比直接运行脚本时的路径查找更耗时,导致IO测试的耗时增加。
优化建议
- 尝试用
--onedir模式打包(而非--onefile),减少临时解压的开销 - 对性能敏感的代码段,用Cython编译为原生扩展模块后再打包,真正实现原生代码级别的加速
- 检查PyInstaller配置,确保它使用的是Python 3.11的解释器及优化后的字节码
内容的提问来源于stack exchange,提问作者Salu Ramos
相关产品推荐
相关产品推荐

