--onedir 模式可将gui程序启动时间从6–10秒降至1.2–2.5秒,因其避免每次启动重复解压;需分发整个文件夹,禁用upx压缩核心dll,并通过懒加载、精简依赖和定位首次import耗时来协同优化。

用 --onedir 替代 --onefile 是最直接有效的提速手段
PyInstaller 默认的 --onefile 模式会在每次启动时,把整个冻结环境从 exe 里解压到临时目录(如 %TEMP%\_MEIxxxxxx),再初始化解释器。这个解压 + 文件系统重建过程无法跳过,且 Windows 杀软常在此阶段深度扫描,导致卡顿 5–15 秒。
--onedir 模式生成一个文件夹,所有依赖一次性解压到位,后续启动直接读磁盘,省掉重复解压开销。实测 GUI 程序启动时间普遍从 6–10 秒降至 1.2–2.5 秒。
- 必须配合
--noconsole(GUI)或保留控制台(CLI),否则窗口可能闪退 - 发布时需分发整个文件夹,不能只传单个 exe
- 可手动删掉
build/和__pycache__/目录,不影响启动速度,只减体积
压缩等级对启动速度基本没影响,但 UPX 可能拖慢加载
PyInstaller 的 --upx 是开关,不是压缩等级调节器;它调用外部 UPX 工具对二进制段(.text/.rdata)做无损压缩。但压缩后 DLL 加载需额外解压页,某些运行时关键 DLL(如 vcruntime140.dll、python39.dll)被 UPX 压缩后,Windows 加载器会多走路径,反而变慢甚至报错。
- 若必须用 UPX,加
--upx-exclude=vcruntime140.dll和--upx-exclude=python3*.dll -
--upx-exclude列表越全越好,宁可不压也不压核心运行时 - 别信“UPX 压缩率越高启动越快”——实际是反相关
模块剥离的关键不是删 import,而是砍隐式依赖链
很多人以为 --exclude-module=numpy 就能甩掉 numpy,但只要代码里有 import pandas,pandas 内部仍会触发 numpy 加载。PyInstaller 的依赖分析是静态的,它抓的是 import 语句,不是运行时行为。
- 优先在干净虚拟环境中打包:用
pipenv或conda create -n mini python=3.9,只装真正需要的包 - 检查
spec文件里的excludes和hiddenimports,删掉自动识别出的冗余项(如matplotlib.tests、sklearn.datasets) - 避免在模块顶层 import 重型库:把
import torch移到函数内部,实现懒加载 - 用
pipreqs . --encoding=utf8生成最小依赖列表,比pip freeze更准
启动慢的真凶常藏在“第一次 import”之后
很多程序看似启动快,但点第一个按钮就卡住 3 秒——这是因为 heavy module 的 import 触发了内部初始化(如 matplotlib 加载字体缓存、requests 注册 SSL 上下文)。这种延迟不属于“启动时间”,但用户感知一样差。
- 用
import time; print(time.time())在每个 import 前后打点,定位耗时模块 - 对确定只在子功能用的模块,封装成函数内 import,例如:
def run_ml_task(): import sklearn # ... - 第三方库自带延迟加载机制的(如
sqlalchemy.create_engine不等于连接数据库),别提前调用
真正难优化的点在于:启动慢是解释器冷启动 + 文件 I/O + 杀软扫描 + 隐式依赖四层叠加的结果,单一手段只能拆一层。你得先确认瓶颈在哪,再选对应解法——比如企业环境里,签名比改代码更管用。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











