Prhub

#21582 Fix HFRunner hang when subprocess dies during init

原始 PR 作者 hnyls2002 合并时间 2026-03-28 12:22 文件变更 1 提交数 2 评论 4 代码增减 +11 / -1

执行摘要

修复 HFRunner 子进程初始化时死亡导致的父进程无限挂起,提升 CI 效率。

PR body 中描述:'When HFRunner.start_model_process crashes during initialization (e.g., HuggingFace 429 rate limiting during get_tokenizer), the subprocess dies before entering its while True loop, so it never puts a result into out_queue. The parent process then blocks forever on out_queue.get() with no timeout, hanging until the CI step timeout kills it (~18 minutes wasted).' 具体示例为 test_cross_encoder_models.py 子进程因加载 tokenizer 时 429 错误崩溃,父进程挂起 18 分钟直到 CI 超时杀死。

该 PR 值得精读,尤其是对于处理多进程通信和故障恢复的场景。关注点:轮询超时值的选择(5 秒)、进程存活检查与队列状态同步的逻辑,以及如何优雅地抛出异常以加速失败检测。

讨论亮点

Review 评论为空,无讨论记录。从提交历史看,第二个提交 'Catch queue.Empty specifically instead of bare Exception' 表明作者在迭代中优化了异常处理,将通用 Exception 改为具体异常,但这未在 review 中讨论。

实现拆解

修改集中在 python/sglang/test/runners.py 文件的 forward 方法。原代码直接调用 out_queue.get() 无限阻塞;新代码引入 while 循环,每 5 秒尝试 out_queue.get(timeout=5),若捕获 queue.Empty 异常,则检查子进程是否死亡(self.model_proc.is_alive())和队列是否空(self.out_queue.empty()),若条件满足则抛出 RuntimeError 包含子进程退出码,从而立即失败而非挂起。

文件 模块 状态 重要度
python/sglang/test/runners.py test/runners modified 6.0

关键符号

forward

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  1. 轮询循环每 5 秒检查可能轻微增加 CPU 开销,但在健康子进程情况下无影响。
  2. 异常处理逻辑依赖子进程状态和队列空检查,若子进程死亡但队列非空(罕见情况),可能错误地不抛出异常,但代码设计确保了同步性。
  3. 超时设置 5 秒可能导致在慢速系统或高负载下误判,但考虑到 CI 环境,这是合理的折衷。

正面影响:显著减少 CI 失败时的等待时间,从长达 18 分钟缩短到约 5 秒,提升测试效率和资源利用率。对终端用户无直接影响,仅影响内部测试运行器;系统稳定性增强,避免因外部 API 错误(如 HuggingFace 429)导致的无响应。影响范围局限于测试模块,不影响生产代码。

轮询开销 状态检查逻辑

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论