s06批处理与调度22 分钟阅读

Schedule Every Step

让 batch 在每一步变化

用 waiting、running 和 token 预算理解 continuous batching。

调度单位变成一步之后,请求可以独立离开,也可以在空位出现时加入。

01不再等待最慢的成员

静态 batch 中,短请求结束后留下空位,却不能立刻补入新请求。continuous batching 在每一轮重新选择工作,完成的请求退出,等待的请求在资源允许时进入。请求仍保留自己的 KV 和进度,改变的是本轮执行集合;这使请求生命周期与一次前向的 batch 成员关系分离。

s06_continuous_batch.py
# Framework pseudocode; phase selection is simplified.
for round in engine_rounds:
    reclaim_finished_requests()
    budget = max_query_tokens
    selected = []
    for request in eligible_requests(waiting, running):
        cost = planned_query_tokens(request)
        if cost <= budget and cache_can_fit(request):
            reserve_planned_state(request)
            selected.append(request)
            budget -= cost
    ready_outputs = execute_scheduled_round(selected)
    apply_ready_updates(ready_outputs)
    # Some sampling/post-processing may still be in flight.
# Inspect upstream NORMAL-mode prefill/decode coordination.

02预算不能只数请求个数

一条长 prompt 的 prefill 和一条单 token decode 对计算与内存的需求不同。调度器既要限制序列数量,也要计算本步 query token 总量,并确认缓存能分配。chunked prefill 把长输入切成多步处理,避免一次占满全部预算。公平性、首次响应和吞吐之间需要明确策略,不能只靠队列顺序碰运气。

03读清 DeepInfer 的步型约束

上游 C++ Scheduler 在 NORMAL 模式下决定本轮做 prefill 还是 decode,并让 DP 组通过投票保持步型一致。它并不等同于任意混合两种 token 的通用片段。ALL 与 ANY 尝试点兼顾无效陪跑和等待上限;理解这些分支前,先追踪 waiting、running、缓存分配和完成回收的变化。

TRY IT YOURSELF

动手想一想

让长 prompt、短 prompt 和正在 decode 的请求同时到达。在固定 token 预算下安排五轮执行,写明每轮不能加入某条请求的具体原因。

把这个机制,加入你的工具箱。