SGLang 调度器 — Request × Batch 可视化

模拟 6 个请求在不同时刻到达。Prefill 优先于 Decode。
Step 1 /
Prefill batch (EXTEND) Decode batch (每请求 1 token) 📥 新请求到达(同 batch 内入队,下一轮参与调度)

核心概念图示

Chunked Prefill 过程

stateDiagram-v2 [*] --> 到达 : Request 到达 到达 --> 匹配 : init_next_round_input() 匹配 --> 一次完成 : extend_input_len ≤ chunk_size 匹配 --> 截断 : extend_input_len > chunk_size, is_chunked += 1 截断 --> Prefill_chunk : EXTEND forward Prefill_chunk --> Stash : 写回 radix tree Stash --> 匹配 : is_chunked > 0 (续 chunk) 一次完成 --> [*] : 进入 decode Stash --> 一次完成 : is_chunked == 0
长 prompt 超过 chunked_prefill_size 时被截断。每个 chunk 的中间结果 stash 回 radix tree,下一 chunk 可命中为前缀缓存。
chunked 状态下请求不输出 token,只有最后一个 chunk 完成后才进入 decode。
注意:续 chunk 时,请求作为 self.chunked_req 保留在调度器中(不进入 waiting_queue),通过 add_chunked_req() 直接加入下一轮 prefill batch 的 can_run_list。这确保了 chunk 之间不穿插 decode。

Request 生命周期

stateDiagram-v2 [*] --> waiting_queue : Tokenizer 发来请求 note right of waiting_queue : #queue-req 统计这里 waiting_queue --> Prefill_Batch : PrefillAdder 选中 (admit) note right of Prefill_Batch : #running-req 统计这里 Prefill_Batch --> waiting_queue : is_chunked > 0 (下一个 chunk) Prefill_Batch --> Decode_Batch : is_chunked == 0 (prefill 完成) note right of Decode_Batch : #running-req 统计这里 Decode_Batch --> Decode_Batch : 未完 (每步 1 token) Decode_Batch --> [*] : finished Decode_Batch --> waiting_queue : retract_decode (L1 满了)
一个 Request 依次穿过 waiting_queue → Prefill Batch(可能多个,chunking) → Decode Batch(持续)。
#queue-req = waiting_queue 中的排队数。#running-req = Prefill/Decode batch 中正在处理的请求数(同名、不同义)。