cuda_launch_blocking=1仅捕获同步cuda错误,无法检测nccl集体通信死锁;需结合nccl_debug、nccl_async_error_handling等环境变量定位分布式阻塞问题。

PyTorch多卡训练卡死,CUDA_LAUNCH_BLOCKING=1 为什么没报错?
因为 CUDA_LAUNCH_BLOCKING=1 只能捕获同步失败的 CUDA kernel 启动错误(比如非法内存访问、越界),但对死锁——尤其是 torch.distributed 的集体通信阻塞(如 all_reduce、barrier)完全无效。此时进程可能全卡在 ncclCommSync 或 cudaStreamSynchronize 上,不抛异常,也不继续。
实操建议:
- 先确认是否真为分布式死锁:用
ps aux | grep python查看进程状态,若大量进程处于D(uninterruptible sleep)或长时间R(running)但无日志输出,大概率是 NCCL 级阻塞 -
CUDA_LAUNCH_BLOCKING=1必须在启动前设置,且仅对当前 shell 有效;若用torchrun或python -m torch.distributed.run,需写成CUDA_LAUNCH_BLOCKING=1 torchrun ...,不能在代码里os.environ["CUDA_LAUNCH_BLOCKING"] = "1" - 搭配
NCCL_ASYNC_ERROR_HANDLING=1使用,它能让 NCCL 在检测到部分 rank 失联时主动报错而非无限等待
排查 torch.distributed.init_process_group 初始化失败导致的隐性死锁
常见现象是:4 卡训练,3 个 rank 成功初始化并打印日志,第 4 个没反应——其实它卡在 init_process_group 的 TCP 握手或共享文件锁上,其他 rank 也在等它,形成闭环等待。
关键检查点:
- 确保所有 rank 使用完全一致的
init_method参数:若用file://,路径必须可被所有进程读写(NFS 或本地共享目录),且文件未被残留进程占用;若用tcp://,主节点(rank 0)必须监听成功,其余 rank 能telnet host port通 -
world_size和实际启动的 GPU 数量必须严格一致;常见错误是脚本里写死world_size=4,但只启动了 3 个进程 - 避免在
init_process_group前做任何 GPU 操作(如torch.cuda.set_device()或张量创建),否则可能触发隐式上下文初始化,干扰 NCCL 初始化顺序
torch.nn.parallel.DistributedDataParallel 的 forward 死锁典型场景
不是模型写错了,而是 DDP 内部依赖 collective op 的时序一致性。最常踩的坑是:在 forward 中混用非 DDP-aware 的自定义同步逻辑。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
例如:
- 手动调用
torch.distributed.all_gather或barrier,但未保证所有 rank 都执行同一分支(比如某 rank 因if rank == 0:跳过,其余 rank 却进入) - 使用
torch.no_grad()时仍调用了需要梯度同步的 DDP 操作(虽不常见,但在混合精度 + custom backward 中可能触发) - 数据加载器(
DataLoader)的num_workers > 0且pin_memory=True,某些 worker 进程意外卡住,导致 main process 在next(iterator)处阻塞,而 DDP 的 backward 又在等这个 batch —— 表象是“训练不动”,实则 I/O 层已卡死
快速验证:临时把 DataLoader 的 num_workers=0,看是否还死锁。如果恢复运行,问题大概率出在 dataloader worker 的 CUDA 上下文或信号处理上。
NCCL 环境变量调试组合拳
单靠 CUDA_LAUNCH_BLOCKING 不够,NCCL 自身提供更精准的阻塞诊断开关:
-
NCCL_DEBUG=INFO:输出每一步 collective op 的发起与完成,能看出哪个 rank 卡在哪条通信上(注意日志量极大,建议配合NCCL_DEBUG_SUBSYS=COLL,INIT缩小范围) -
NCCL_ASYNC_ERROR_HANDLING=1:强制 NCCL 在超时后主动 abort,而不是静默 hang;配合NCCL_TIMEOUT=60(单位秒)可设为合理阈值 -
NCCL_IB_DISABLE=1:禁用 InfiniBand,强制走 PCIe + TCP,排除 RDMA 配置问题(尤其在云服务器或虚拟化环境) - 所有 NCCL 变量必须在
init_process_group前设置,且对所有 rank 完全一致;建议统一写在启动命令最前面:NCCL_DEBUG=INFO NCCL_ASYNC_ERROR_HANDLING=1 torchrun ...
真正棘手的是 NCCL 日志里出现 NET/Socket: Connection reset by peer 或 timed out waiting for operation —— 这说明底层网络或驱动已出问题,不是代码能绕过的。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










