能调试,但必须满足三个硬性条件:VSCode Python扩展≥2023.10.0、debugpy≥1.6.0、launch.json中同时启用"subProcess":true和"console":"integratedTerminal";缺一不可,否则子进程断点全失效。

能调试,但必须满足三个硬性条件:VSCode Python 扩展 ≥ 2023.10.0、debugpy ≥ 1.6.0、launch.json 中同时启用 "subProcess": true 和 "console": "integratedTerminal"。缺一不可,否则子进程断点全失效。
launch.json 必须加的两项配置
只写 "subProcess": true 不够,VSCode 多进程调试依赖终端上下文注入调试器。Windows/macOS 上 spawn 启动方式若无终端,子进程会静默退出;Linux 上即使 fork 也可能因缺少环境变量导致 debugpy 注入失败。
-
"subProcess": true—— 让 debugpy 自动监听所有由multiprocessing、concurrent.futures或subprocess派生的新进程 -
"console": "integratedTerminal"—— 强制子进程继承终端环境,避免因sys.stdout不可用或信号处理异常而崩溃 - 建议同步设
"justMyCode": false,否则子进程里调用的第三方库函数内断点可能被跳过
代码侧必须避开的三个坑
配置再对,代码写法不对照样断点不命。常见失效不是 VSCode 问题,而是 Python 运行时没让 debugpy 有机会介入。
- 启动方法必须显式指定:
mp.set_start_method('spawn')(Windows/macOS 强制;Linux 上也推荐,fork可能复制造成调试器状态错乱) - 子进程入口函数必须定义在模块顶层,不能嵌套在
if __name__ == '__main__':块里,否则子进程导入失败,根本起不来 - 禁止用
os.fork()或自定义fork行为——debugpy 不拦截原生系统调用,只 hook Python 层的进程创建逻辑
断点打在哪才有效
子进程断点不是随便一行都能停。VSCode 调试器需要在 Python 字节码执行前完成注入,所以太晚打的断点会被跳过。
立即学习“Python免费学习笔记(深入)”;
- 断点必须打在子进程函数体第一行可执行语句上,比如
def worker():下面紧跟着的import logging或conn = get_db_connection() - 别打在
assert、return或空行后——这些位置 debugpy 可能尚未完成线程/进程上下文切换 - 如果用了
concurrent.futures.ProcessPoolExecutor,断点要落在提交给submit()的那个函数内部,而不是executor.map()调用处
调试时看不到子进程变量?切换调用栈就行
VSCode 默认只显示当前选中线程/进程的变量,不是所有进程变量堆在一起。子进程停住后,左侧 CALL STACK 面板会出现类似 Process-1、Process-2 的条目。
- 点击对应子进程名,Variables 面板立刻刷新为该进程的局部作用域和全局变量
- 如果面板为空,说明该进程还没真正进入断点位置——检查是否卡在
mp.set_start_method()之前,或子进程函数根本没被调用 - 注意:子进程 PID 会出现在调试控制台日志里,形如
Debug adapter process launched with pid: 12345,可用于交叉验证
最常被忽略的是 spawn 启动方式与模块顶层函数的耦合性——哪怕 launch.json 全对,只要子进程函数藏在 main() 里,VSCode 就永远 attach 不上那个进程。这不是配置问题,是 Python import 机制决定的硬约束。


















