print() 在多卡训练中重复输出是因为每个 GPU 对应独立进程,所有 rank 均执行 print;应仅让 rank 0(主进程)输出,通过 torch.distributed.is_initialized() 和 get_rank() 判断实现。

为什么 print() 在多卡训练里会重复输出?
PyTorch 的 torch.distributed.launch 或 torchrun 启动多进程时,每个 GPU 对应一个独立进程,print() 会在所有进程中执行。你看到日志刷屏,不是 bug,是每个 rank 都在 stdout 上写一遍。
真正需要的不是“禁用其他卡打印”,而是“只让 rank 0(主进程)输出”。但要注意:rank 0 不一定对应 GPU 0——它只代表分布式组里的第一个参与进程,通常由启动脚本指定(如 --nproc_per_node=4 时,rank 0 是第一个启动的子进程)。
常见错误现象:
- 日志每行出现 4 次(4 卡训练)
- tqdm 进度条错乱或卡死
- logging.info() 写入文件时内容混杂、重复
如何安全地只让主进程执行 print 和 logging?
最轻量、最可靠的方式是封装一个条件判断逻辑,不依赖额外库,也不修改全局 print 行为:
- 用
torch.distributed.is_initialized()判断是否已进入分布式模式(避免单卡调试时报错) - 用
torch.distributed.get_rank()获取当前进程 rank,仅当rank == 0时执行输出 - 不要用
os.environ.get("LOCAL_RANK")判断——它只表示本机上的 GPU 编号,和分布式 rank 不等价(例如 2 节点 × 2 卡时,LOCAL_RANK=0 可能对应 global rank=2)
示例:
def print_on_main(*args, **kwargs):
if not torch.distributed.is_initialized() or torch.distributed.get_rank() == 0:
print(*args, **kwargs)
<h1>使用</h1><p>print_on_main(f"Epoch {epoch}, loss: {loss.item():.4f}")
</p>
使用 tqdm 时怎么避免多进度条打架?
tqdm 默认在每个进程都渲染自己的进度条,不仅干扰视觉,还可能因抢占终端控制权导致卡顿或崩溃。关键不是“隐藏其他条”,而是“只让 rank 0 渲染”。
实操建议:
- 始终传入
disable=(rank != 0)参数,而不是靠 if 包裹整个tqdm()调用——否则数据加载器迭代行为可能不一致(尤其配合DataLoader(..., num_workers>0)时) - 若用
from tqdm.auto import tqdm,它会自动选tqdm.tqdm或tqdm.tqdm_notebook,但不会自动处理分布式,仍需手动加disable - 注意:即使
disable=True,tqdm仍会正常迭代,只是不显示 UI,不影响功能
示例:
rank = torch.distributed.get_rank() if torch.distributed.is_initialized() else 0
for batch in tqdm(dataloader, disable=(rank != 0), desc="Train"):
# ...
日志写入文件时还要注意什么?
如果用 logging.FileHandler,多个进程同时 open 同一个文件并 write,极易导致内容错位、覆盖或损坏。即使加了 rank == 0 判断,也要确认:
- 文件路径是否被所有进程共享(比如 NFS 或本地路径)
- 是否有其他进程(如 tensorboardX 后台线程)也在写同名文件
更稳妥的做法:
- 主进程写日志到
train_rank0.log,其他进程完全不 touch 日志文件 - 若需汇总所有 rank 的调试信息(比如梯度 norm),改用
torch.distributed.all_gather收集后由 rank 0 统一写入,而非各自 fopen - 避免在
__del__或 atexit 中写日志——多进程退出顺序不确定,容易报RuntimeError: Attempting to use uninitialized CUDA
复杂点往往藏在边界:比如混合精度训练中 scaler.state_dict() 打印、DDP 模型的 module.named_parameters() 遍历,这些操作本身不耗时,但若没加 rank 判断,就会在每张卡上重复执行+输出,浪费资源且掩盖真实问题。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











