Core optimizations
Continuous batching
Reschedule every model forward so finished sequences free a slot on the next step, not when the longest one ends.
Continuous batching (also called in-flight batching or iteration-level scheduling) comes from Orca (OSDI 2022). The scheduler does not commit to a batch for the lifetime of its longest sequence. It runs one model forward, then removes finished sequences, admits waiting ones, and repeats.
Finished slots are reused on the next step — typically tens of milliseconds later, not seconds later. That is the jump from a toy server to vLLM, SGLang or TensorRT-LLM.
Concept
An iteration is one forward pass of the model. Decode sequences contribute about one token each. A prefill contributes many tokens, or a chunk of them.
The big idea
Static batching is a bus that will not board anyone until it returns to the depot. Continuous batching is a bus that opens the door at every stop. The analogy breaks at memory: you can only board a new passenger if a KV seat is free.
Walking through one iteration
Every step, a production scheduler roughly answers:
| Decision | Question | Typical constraint |
|---|---|---|
| Admission | Can a waiting request join? | Free KV blocks, max_num_seqs, fair queues |
| Token budget | How many tokens run this step? | max_num_batched_tokens (prefill + decode) |
| Preemption | Who gets paused if memory is tight? | Priority, FCFS, remaining length |
| Recovery | After preemption, swap or recompute? | See swap vs recompute |
Orca also introduced selective batching: attention is irregular across requests (different KV lengths), while MLP matmuls can still batch tokens. Modern engines do the same with custom attention over a ragged set of sequences (PagedAttention) and batched GEMMs for the rest.
Anyscale's widely cited measurements put vLLM-style continuous batching, with good memory management, around up to ~23× throughput versus Hugging Face Transformers-style generation on the same hardware. Matmuls did not get 23× faster. The GPU stopped idling and stopped refusing work that would have fit.
Important
Continuous batching needs flexible KV memory. If you pre-reserve a contiguous max-length KV slab per sequence, you run out of GPU memory long before you run out of compute. That is why PagedAttention and continuous batching traveled together.
Tuning knobs
Names vary; the ideas transfer to SGLang and TensorRT-LLM.
max_num_seqs: cap on concurrent sequences. Raise it to improve throughput until you hit KV memory or latency SLOs. Lower it to protect TPOT under load.max_num_batched_tokens: cap on tokens per iteration. Higher favors throughput and long prefills. Lower bounds step time and helps tail latency.- Queue policy: FCFS vs priority; whether to admit a huge prefill when many decodes are active.
- Preemption mode: recompute vs swap.
A practical loop: fix model, GPU and quantization; sweep concurrency with a realistic length mix; plot goodput under your TTFT/TPOT limits; raise max_num_seqs until goodput flattens or SLOs break; then adjust the token budget.
Common mistakes
- Setting
max_model_lenso high that KV admits only a handful of sequences. Paging helps, but the cap still shapes planning. - Optimizing for peak tokens/s. Product cares about p95 TTFT and TPOT. See benchmarking.
- Forgetting preemption. When KV fills, the scheduler must pause someone. That is a feature, not a crash.
Check yourself
- When does a finished sequence free its slot under continuous batching? Answer: on the next iteration, typically tens of milliseconds later.
- Why does continuous batching need paged KV? Answer: a contiguous max-length reservation runs out of memory before the GPU runs out of compute.
Key takeaways
- Reschedule every iteration so finished sequences free capacity immediately.
- Admission is limited by KV blocks,
max_num_seqsandmax_num_batched_tokens. - Tune those knobs against latency SLOs, not peak tokens/s.
Further learning
Next, stop long prompts from stalling decode with chunked prefill. For the memory side, read PagedAttention.
Related
Batching and continuous batching
Why batching amortizes weight reads, how static and dynamic batching waste GPU time, and how iteration-level continuous batching plus chunked prefill unlocks 10–20× throughput.
Static and dynamic batching
Padding and tail idle waste GPU slots, and a timeout still locks the batch until the longest sequence ends.
PagedAttention and KV memory management
How reserving contiguous max-length KV wastes most of GPU memory, and how fixed-size KV blocks with block tables eliminate fragmentation and unlock sharing.