Skip to main content
Fully async rollout splits Miles into two concurrent loops:
  1. A background rollout worker keeps SGLang generation in flight and pushes completed samples into a queue.
  2. The trainer drains the queue, runs optimizer steps, and syncs updated weights back to rollout engines.
When rollout and training take similar time, per-iteration wall time moves from rollout_time + train_time toward max(rollout_time, train_time).

When to use it

The mode is especially useful for long-context math, tool-use, and agentic workloads where generation dominates the iteration.

Enable it

Switch the entrypoint from train.py to train_async.py and provide a rollout function that owns the background worker:
Everything else belongs in the same argument groups as a synchronous run.

Queue model

The queue is the contract. If it stays populated, the trainer does not wait for generation. If it is empty, rollout is still the bottleneck and async cannot hide it.

Tuning knobs

The reference worker caps its output queue at 1000 groups, so if training is slower than rollout the producer eventually blocks rather than growing the queue without bound. If the queue stays at zero, rollout is the bottleneck — scale rollout capacity or lower per-sample generation cost.

What to monitor

The reference worker logs progress to stdout, not wandb. Useful lines to grep for:
Treat large staleness windows as a training-quality signal, not just a performance signal. Fast P2P weight transfer keeps the rollout engines closer to the latest actor weights so fewer groups get recycled by --max-weight-staleness.

Example implementation

For a complete Qwen3 launch script and worker implementation, see the Fully Async Rollout example.