The clip is always the same shape. Five terminals, one loop, Rust prints the time first, and the caption says "100x". The clip never says what the loop did, or whether the program was waiting on a socket the whole time.
This post is a model for one kind of work: a CPU-bound checksum in memory. No HTTP. No disk. No Postgres. The interesting part is not the screenshot. It is which kind of language is running the loop.
Same checksum loop, three ways to reach the CPU. Interpreters pay a dispatch tax every trip. Go compiles ahead of time but keeps a GC. Rust compiles to machine code with no GC on this path.
At 1× the balls stay readable. Slide toward 100× when you want Rust to look unfair. The slider only changes playback. It does not change the language ratios.
Three kinds of language
Interpreted high-level: Python, PHP, JavaScript. You ship source. CPython, Zend, or V8 still walks bytecode (or JITs after warmup) while the loop runs. That dispatch cost is why these three sit at about 1×, 3×, and 13×.
Compiled high-level: Go. The compiler builds a native binary ahead of time, so the hot path is machine code. A garbage collector and runtime still ride along. That is why Go jumps to about 53× without matching Rust.
Compiled low-level: Rust. rustc and LLVM also emit machine code ahead of time. On this checksum there is no GC on the path: ownership did that work at compile time. That is the ~115× lane.
The program under test
Here is the job in Python. The other languages do the same math: walk 0 .. n-1, accumulate i * i, keep a 32-bit mask so the optimizer cannot delete the loop.
def hrr_checksum(n: int) -> int:
total = 0
for i in range(n):
total = (total + i * i) & 0xFFFFFFFF
return total
print(hrr_checksum(50_000_000))
Same shape in Rust:
fn hrr_checksum(n: u64) -> u32 {
let mut total: u32 = 0;
for i in 0..n {
total = total.wrapping_add(((i * i) as u32));
}
total
}
fn main() {
println!("{}", hrr_checksum(50_000_000));
}
I am not timing a framework, an ORM, or a JSON handler. If your real p99 is waiting on the network, this post is the wrong tool.
What the model is measuring
Python is the 1× baseline. The ratios below are relative throughput for that loop class on stock runtimes, rounded so the race stays readable.
Language
Relative speed
What usually eats the time
Python
1×
Interpreter dispatch per iteration
PHP
3×
Still managed, often a bit tighter than CPython here
JavaScript
13×
JIT warms up and accelerates the hot path
Go
53×
Compiled binary, GC still in the picture
Rust
115×
Compiled binary, no GC on this path
PHP stays near the managed cluster (~3×). JavaScript’s JIT pulls it ahead of PHP (~13×) without catching a compiled binary. Go is clearly ahead (~53×). Rust is clearly ahead of Go (~115×, about 2× Go).
Why the interpreted lane trails
CPython and the PHP CLI walk bytecode (or similar) for every trip around the loop. Stock JavaScript is still a managed runtime, even when V8 helps after warmup. On ordinary CPU work they trail a compiled binary. That is why those three balls stay behind Go and Rust in the figure.
Why Go and Rust pull away, and why they split
Go and Rust both ship machine code for this loop, so they leave the interpreted lane behind. Go still carries a GC runtime. Rust does not on this path. That gap is the difference between ~53× and ~115× here: not "Go is slow," and not a web framework benchmark.
None of that says a Rust HTTP handler beats a Go one when both wait on the same database.
When the chart lies
Three cases where the figure should not decide the stack:
I/O bound work. Network, disk, and locks dominate. A faster loop language does not move the p99.
One-shot scripts. A migration you run once finishes in Python before I have a Rust project compiling.
Team fit. If nobody wants a borrow checker in review, Go or JavaScript will ship the service, and the micro-loop inside it is rarely the thing on fire.
I reach for Rust when the same CPU loop sits on the hot path, the data is in memory, and I can afford the compile. I do not reach for it to win a screenshot.
On this post
Comments
A reply stays under the note it answers.
No comments yet.
If you have a note on Why Rust Finishes That Loop Before Python, PHP, JavaScript, and Go, sign in and leave it.