How Rust Achieves Superior Loop Performance Over Python and Go

How Rust Achieves Superior Loop Performance Over Python and Go EduTechBuddy.com © edutechbuddy.com
How Rust Achieves Superior Loop Performance Over Python and Go © edutechbuddy.com
Explore why Rust dramatically outpaces Python, PHP, JavaScript, and Go in CPU-bound checksum loops by examining language execution models, runtime overhead, and practical code examples.

Developers often see striking speed differences when running CPU-bound tasks in different programming languages. Running a simple checksum loop—processing millions of numbers and adding up results—shows how language design and runtime overhead affect real-world performance. Rust consistently finishes these loops much faster than Python, PHP, JavaScript, or Go.

Why Execution Model Matters

Programming languages handle code execution in distinct ways. Interpreted languages like Python, PHP, and JavaScript process source code or bytecode as the program runs. Each loop iteration brings interpreter overhead, which slows things down. JavaScript's just-in-time (JIT) compilation can optimize hot code, but only after the runtime warms up and identifies which paths to accelerate.

Compiled languages such as Go and Rust produce native machine code before execution. This removes interpreter overhead from the loop. Go, however, includes a garbage collector (GC) and a runtime that stay active, while Rust's ownership model lets it skip GC for in-memory calculations like these. The GitLab Engineering Handbook notes, "Rust has no garbage collector and frees memory as soon as it is no longer used." Rust’s speed in tight CPU-bound loops comes from ahead-of-time native compilation, static typing, and the lack of a tracing garbage collector in the running program. Rust’s ownership and borrowing rules move memory-safety checks to compile time, so runtime code avoids interpreter dispatch and most automatic memory management.

Go also compiles to native code, but its runtime brings a concurrent garbage collector and exposes GC-related metrics like collection frequency and pause duration. Go’s garbage collector runs concurrently and checks which objects are still reachable. The GOGC setting, a percentage of the live dataset, defaults to 100% and aims for newly allocated heap to match the live heap before collection pressure rises. This can affect memory use and CPU load in allocation-heavy services, especially when large datasets stay in memory. A loop over integer variables that doesn't allocate may leave little or nothing for the collector to handle. Uber Engineering points out, "Go runtime invokes a concurrent garbage collector at periodic intervals unless there is a triggering event before it."

Benchmarking the Checksum Loop

The main comparison uses a checksum function that loops from 0 to n-1, adding i * i to a total with a 32-bit mask to keep the optimizer from skipping the loop. Here’s the Python version:

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))

The Rust version uses the same logic:

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));
}

Each language runs this loop with the same workload, so the comparison focuses on execution models and runtime overhead. Python’s interactive tools, like %timeit, measure short expressions and automatically increase repetitions for fast operations. This shows that timing methods are central to reliable Python performance measurement. The IPython documentation gives an example timing of about 7.88 nanoseconds per loop for 1+1 in a specific environment, while a list comprehension over 5,000 values clocks in at about 608 microseconds per loop. These examples show that benchmark results must specify the interpreter version, hardware, repetition method, and whether setup work is included.

Relative Performance and Overhead

Using Python as the baseline (1×), the relative speeds for this loop are:

LanguageRelative speedPrimary overhead
Python | 1× | Interpreter dispatch per iteration
PHP | 3× | Managed runtime, tighter than CPython
JavaScript | 13× | JIT acceleration after warmup
Go | 53× | Compiled binary, GC and runtime present
Rust | 115× | Compiled binary, no GC on this path

Interpreted languages are held back by the cost of dispatching each loop iteration. JavaScript's JIT can speed up hot code, but compiled binaries still run faster. Go’s ahead-of-time compilation brings a big speed boost, though its garbage collector adds some overhead. Rust, compiling straight to machine code and using ownership for memory management, delivers the highest throughput in this test.

Production data from the GitLab Engineering Handbook gives real-world infrastructure figures for Rust and Go. For Grab’s Counter Service, the Rust rewrite reportedly used about 4.5 CPU cores compared with 20 cores for Go at similar p99 latency, which means roughly 77.5% fewer cores and about 70% infrastructure-cost savings. Discord saw latency spikes when Go’s garbage collector scanned a large in-memory cache, but a Rust rewrite removed those spikes. Cloudflare’s Pingora, a Rust-based HTTP proxy, is described as using about 70% less CPU and 67% less memory than NGINX for the same traffic. These numbers back up the claim that runtime and memory-management choices can affect service efficiency, as reported in the GitLab Engineering Handbook.

What This Means for Developers

When a CPU loop is the bottleneck and data stays in memory, language choice can make a huge difference in performance. Rust’s approach—compiling to machine code with no garbage collector on the loop’s path—lets it outperform Go and leave interpreted languages far behind. These results, though, apply to CPU-bound, in-memory workloads. If an application spends most of its time waiting on network or disk I/O, the language’s loop speed won’t matter much for overall performance.

Development speed and team preferences also play a role. For quick scripts or one-off tasks, Python may be more practical even though its loops run slower. When the loop is truly hot and performance is critical, Rust’s model gives a clear edge. Production observability systems, like those described in Jaeger’s operations documentation, treat Go garbage collection as an operational variable. Metrics for GC duration and frequency let operators track how often collection happens and how long it takes.

Practical Learning Takeaways

Knowing how language execution models and runtime overhead affect performance helps developers write efficient code. Trying out similar checksum loops in different languages lets learners see these differences directly. Developers who want to deepen their programming knowledge can explore topics like interpreter design, JIT compilation, garbage collection, and ownership models to get more context for language selection and optimization.

Readers interested in testing their programming skills further can try the advanced Python developer quiz to check their understanding of core concepts.

This analysis uses a model checksum loop and does not represent the performance of frameworks, databases, or I/O-bound workloads. For the full interactive version and more context, see the original article at harun.dev.

Camila Ferreira Editor EduTechBuddy.com
Co-Founder

Camila Ferreira

Camila Ferreira is the Co-Founder of EduTechBuddy, where her editorial focus is programming education and practical software development skills. Her primary subjects include Python programming, Git version control, and the fundamental concepts beginners need to understand when working with code.