This demo illustrates how CPU-intensive work can block the Tokio async runtime, making it appear like I/O stalling when the executor is actually maxed out.
CPU-bound work slipped into async code looks identical to I/O stalling, but the root cause is different:
- I/O stalling: Network/disk operations are slow
- Runtime blocking: CPU work hogs the executor threads
The tough bit wasn't writing async code, it was figuring out when a future was hogging the runtime. Even with Tokio Console, finding the real culprit can be a goose chase.
# BAD: CPU work blocks the runtime
cargo run
# GOOD: CPU work uses spawn_blocking
cargo run -- --blockingWithout --blocking: The "fast task tick" stops printing for ~12 seconds while CPU work runs.
With --blocking: The "fast task tick" continues printing every 200ms because CPU work runs on a thread pool.
When async tasks stop responding but there's no obvious I/O bottleneck, check for CPU-intensive work running directly on the async runtime. Use spawn_blocking to move CPU work to dedicated threads.