断点不触发需确认使用debugpy而非已弃用的ptvsd,启用"subProcess": true支持子线程调试,并每次修改代码后全量重启调试会话。

断点不触发?确认 VSCode 使用的是 Python 官方调试器(ptvsd 已弃用)
VSCode 默认的 Python 扩展调试器(基于 debugpy)原生支持多线程断点,但前提是没手动降级或误配成旧版 ptvsd。如果你发现主线程能断、子线程进不去,大概率是调试器版本或配置问题。
检查方式:启动调试后看调试控制台顶部日志,应含类似 debugpy version 1.6.0+;若出现 ptvsd 或报错 Failed to initialize debugger,说明环境异常。
- 确保已卸载
ptvsd:pip uninstall ptvsd - 重装最新
debugpy:pip install --upgrade debugpy - 在
.vscode/launch.json中确认"type": "python",且无"debugLauncherPath"等手动指向旧调试器的字段
子线程断点失效?必须启用 subProcess 调试选项
默认情况下,debugpy 只附加到主进程,所有 threading.Thread 启动的子线程不会被自动监控——这不是 bug,是设计选择。要让子线程内断点生效,需显式开启子进程/子线程调试支持。
在 .vscode/launch.json 的调试配置中添加:
立即学习“Python免费学习笔记(深入)”;
{
"configurations": [
{
"name": "Python: Current File (with subprocess)",
"type": "python",
"request": "launch",
"module": "your_module",
"justMyCode": false,
"subProcess": true
}
]
}
-
"subProcess": true是关键项,它让 debugpy 监听所有由当前 Python 进程派生的线程(包括threading.Thread和multiprocessing.Process) -
"justMyCode": false非必需,但建议开启,避免因第三方库代码跳过断点 - 注意:启用后首次断点可能稍慢,因为 debugpy 需动态注入线程钩子
变量窗口看不到子线程局部变量?切换调试目标线程再查看
VSCode 调试界面默认只显示当前暂停线程的栈帧和变量。当多个线程同时停在断点时,你看到的 Variables 面板内容取决于「当前选中的调用栈帧」,而非所有线程的合并视图。
操作路径:调试时左侧 CALL STACK 面板会列出所有暂停线程(如 Thread-1, Thread-2, MainThread),点击任一线程名即可切换上下文。
- 每个线程有自己的局部变量作用域,切换后
Variables面板实时刷新 - 全局变量(
global或模块级变量)在任意线程上下文中都可见,但值反映的是最新写入状态(注意竞态) - 若某线程未暂停,其局部变量不可见——这是正常行为,不是调试器限制
为什么改了代码断点还停在老位置?热重载不适用于多线程调试
VSCode 的调试会话一旦启动,就锁定当前加载的 .py 文件字节码。你在调试中途修改源码并保存,不会触发重载;子线程可能仍在执行旧版本函数,导致断点偏移、跳过甚至崩溃。
- 每次修改涉及多线程逻辑的代码后,必须停止调试(
Shift+F5),再重新启动(F5) - 不要依赖「重启调试会话」按钮(循环箭头图标),它不强制重载模块,仍可能复用旧线程栈
- 特别注意
import缓存:如果子线程动态导入模块,修改后需清空__pycache__或设PYTHONDONTWRITEBYTECODE=1
多线程调试真正的复杂点不在设置,而在于「时间不可逆」——你无法回放线程调度顺序,也无法保证每次暂停的线程组合一致。把 subProcess 打开、每次改完就全量重启、切线程看变量,这三步漏掉任何一环,都会让你以为调试器坏了。


















