执行摘要
修复 Megatron 服务器并行 update_from_disk 问题
修复并发 update_from_disk 可能导致的资源竞争和错误,确保多个请求同时到达时的正确性。
值得精读,特别是锁和 future 的使用方式。建议在后续 PR 中补充对应的并发测试。
该 PR 无 review 评论。
修复并发 update_from_disk 可能导致的资源竞争和错误,确保多个请求同时到达时的正确性。
值得精读,特别是锁和 future 的使用方式。建议在后续 PR 中补充对应的并发测试。
该 PR 无 review 评论。
| 文件 | 模块 | 状态 | 重要度 |
|---|---|---|---|
slime/backends/megatron_utils/server/megatron_server.py |
服务端 | modified | 6.91 |
slime/backends/megatron_utils/server/megatron_server.py
core-logic
核心变更文件,修改了 update_from_disk 处理逻辑,引入锁和请求合并机制。
# slime/backends/megatron_utils/server/megatron_server.py
# 在 _build_http_app 中,扩展 update_state 并引入锁
async def update_from_disk(request: web.Request) -> web.Response:
if update_from_disk_fn is None:
return _json_error("update_from_disk is not available during warmup", 503)
payload = await _read_json_payload(request)
model_path = _get_update_model_path(payload)
if model_path is None:
return _json_error("missing model_path", 400)
# 使用锁保护状态检查与更新
async with update_lock:
# 如果模型路径与当前已加载的相同,直接跳过
if getattr(args, "load", None) == model_path:
return web.json_response({"ok": True, "model_path": model_path, "skipped": True})
if update_state["in_progress"]:
# 如果已有相同路径的更新在进行中,则等待其完成(请求合并)
if update_state["updating_model_path"] == model_path and update_state["update_future"] is not None:
update_future = update_state["update_future"]
coalesced = True
else:
# 不同路径的更新冲突
updating_model_path = update_state["updating_model_path"]
return _json_error(f"update_from_disk is already in progress for {updating_model_path}", 409)
else:
# 无进行中更新,创建新 future 并记录状态
update_future = asyncio.get_running_loop().create_future()
update_state["in_progress"] = True
update_state["updating_model_path"] = model_path
update_state["update_future"] = update_future
coalesced = False
if coalesced:
# 等待已有的更新结果,并添加 coalesced 标记
result = await asyncio.shield(update_future)
if result.get("ok") is True:
result = dict(result)
result["coalesced"] = True
return web.json_response(result)
return _json_error(result.get("error", "update_from_disk failed"), int(result.get("status", 500)))
timeout_s = _get_update_timeout_s(payload, args)
result = None
error = None
try:
before_loads = await _wait_until_idle(sample_manager, timeout_s)
update_result = await asyncio.to_thread(update_from_disk_fn, model_path)
after_loads = await _ray_get(sample_manager.get_loads.remote())
except TimeoutError as e:
error = {"ok": False, "status": 503, "error": str(e)}
except Exception as e:
error = {"ok": False, "status": 500, "error": f"update_from_disk failed: {e}"}
finally:
if error is None:
result = {
"ok": True,
"model_path": model_path,
"before_loads": before_loads,
"after_loads": after_loads,
"update_result": update_result,
}
# 同步 args 中的模型路径
args.load = model_path
args.ref_load = model_path
async with update_lock:
if result is not None:
update_state["in_progress"] = False
update_state["updating_model_path"] = None
update_state["update_future"] = None
update_future.set_result(result)
else:
update_state["in_progress"] = False
update_state["updating_model_path"] = None
update_state["update_future"] = None
update_future.set_result(error)
if error:
return _json_error(error["error"], error["status"])
return web.json_response(result)
当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。
该 PR 修改了 Megatron 服务器的核心更新逻辑,增加了锁和 future 机制,可能引入死锁风险。但通过 asyncio.Lock 和 asyncio.shield 的使用,风险可控。测试覆盖不足,建议补充并发测试。
影响范围局限于 Megatron 服务器的 update_from_disk 端点,不会影响其他模块或用户接口。变更提升了并发场景下的稳定性和响应效率。
当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。
参与讨论