Python应用启动慢八成因模块加载,仅被import的模块会自动生成.pyc;入口脚本如main.py默认不编译,需用compileall递归预编译并确保未禁用字节码写入。

Python 应用启动慢,八成问题出在模块加载上;预编译 .pyc 文件能直接减少 3–10 倍的模块加载耗时,但不是所有 .py 文件都会自动生成 .pyc,也不是生成了就一定被用上。
哪些文件会被自动编译成 .pyc?
只有被 import 的模块才会触发自动编译——也就是说,你直接 python main.py 运行的入口脚本,**默认不会生成 .pyc**(除非它又被别的模块 import)。而它 import 的所有模块(比如 requests、numpy 或你自己写的 utils.py),只要首次加载,就会在 __pycache__ 下生成对应版本的 .pyc 文件。
常见误区:
-
main.py自身不被 import → 不进__pycache__→ 每次启动都得重新编译 -
__pycache__目录权限不对(如只读)→ 编译失败 → 回退到源码解析,速度归零 - 不同 Python 版本共用同一目录 →
baz.cpython-310.pyc和baz.cpython-312.pyc并存,但解释器只认匹配的那一个
手动预编译整个项目:用 compileall 而不是单个 py_compile
对部署环境或容器镜像,应该在构建阶段一次性编译全部模块,避免运行时现场编译。推荐用 compileall 模块递归处理:
立即学习“Python免费学习笔记(深入)”;
python -m compileall -f -d __pycache__ ./myapp/
关键参数说明:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
-
-f:强制重编译,跳过时间戳比对(防止因文件系统时间不准漏编译) -
-d __pycache__:指定缓存根目录(默认就是当前目录下的__pycache__) - 路径末尾不加
/可能导致某些子包被忽略,建议统一用./myapp/
注意:compileall 不会编译顶层脚本(如 ./myapp/run.py),它只处理被当作模块导入的 .py 文件。如果 run.py 是入口,需单独用 py_compile.compile('run.py') 补上。
python -B 和 PYTHONDONTWRITEBYTECODE 会彻底禁用 .pyc
这两个机制常被误用于“清理缓存”,结果反而让每次启动都变慢:
-
python -B script.py:禁止写入任何.pyc,包括__pycache__和同目录的旧式module.pyc -
PYTHONDONTWRITEBYTECODE=1 python script.py:效果同-B,且影响所有子进程 - CI/CD 流水线里设了这个环境变量 → 镜像里没
.pyc→ 容器一启就编译,首启延迟飙升
真正需要“不写缓存”的场景极少,比如调试时想确保每次都读源码;生产环境应始终允许生成 .pyc,并把编译动作前移到构建期。
优化级别影响 .pyc 内容,但不改变加载速度
python -O 或 python -OO 生成的 .pyc 文件体积更小(移除 assert、docstring),但加载速度和普通 .pyc 几乎一致。实测差异在毫秒级,远不如“有没有 .pyc”这个因素关键。
真正值得做的只有两件事:
- 确保所有被 import 的模块都有预编译好的
.pyc(用compileall扫一遍) - 确认运行环境没设
-B或PYTHONDONTWRITEBYTECODE
至于 __pycache__ 目录是否要打包进 Docker 镜像?要。否则容器启动时发现没有缓存,又得现场编译——预编译就白做了。

















