Rust vs Python Performance 2026: 10x to 100x Faster, When It Matters

Max WellsMax WellsFounder of Rustify
Rust vs Python Speed

Rust is 10–100x faster than Python for CPU-bound work in 2026, uses 5–10x less memory, and starts in milliseconds. PyO3 lets you keep Python's ecosystem while running Rust in the performance-critical hot path.

If your workload is CPU-bound, Rust is often the right answer. If your workload is database-bound, script-like, or mostly orchestration around existing C/CUDA libraries, Python is often still good enough.

By Max Wells, updated August 2026

TL;DR: Rust is 10–100x faster than Python for CPU-bound work. But raw speed is rarely the right metric. The more important questions are: where does the performance gap actually hurt you, and can you get Rust's performance while keeping Python's ecosystem? The answer to the second question is yes; via PyO3. The most performant Python AI tools (Polars, Pydantic v2, HF Tokenizers, Ruff) use Rust underneath for exactly this reason.

  • Raw CPU performance: Rust 10–100x faster than Python for compute-heavy work
  • I/O-bound work: gap narrows to 2–5x; often irrelevant for database-bound services
  • Memory: Rust uses 5–10x less memory: no Python runtime, no GC overhead
  • Startup time: Rust binary in milliseconds; Python + imports in seconds
  • The smart path: PyO3 lets you keep Python's API while running Rust in the hot path

Why Is Python Slow for CPU-Bound Work?

Python is slow for CPU-bound work for three structural reasons: interpretation overhead, the Global Interpreter Lock, and dynamic typing. None of these can be fully patched without changing the language itself.

The Global Interpreter Lock (GIL)

CPython (the standard Python implementation) uses a GIL: a mutex that allows only one thread to execute Python bytecode at a time. This means Python cannot parallelize CPU-bound work across multiple cores with threads. On a 32-core server, a CPU-bound Python program uses one core. Rust uses all 32.

Interpretation Overhead

Python is interpreted. Each operation (adding two integers, calling a function, indexing a list) goes through layers of abstraction: type lookup, attribute resolution, method dispatch. Rust compiles to native machine code that runs directly on the CPU with no runtime dispatch overhead.

Dynamic Typing

Python determines types at runtime. Every operation requires a type check. Rust determines types at compile time and emits optimized machine code specific to those types; no runtime type checks, no boxing. This difference alone accounts for a significant portion of the performance gap on computation-heavy workloads.

Python 3.13+ introduces experimental free-threaded mode (no GIL). It helps with some workloads but does not close the fundamental gap with compiled code. The interpretation overhead and dynamic typing costs remain.

Which One Should You Use in 2026?

Choose Rust if your bottleneck is real CPU work, memory footprint, or concurrency under load. Choose Python if your bottleneck is iteration speed, ecosystem access, or glue code around already-optimized libraries.

Use this quick filter:

  1. Choose Rust if your application spends most of its time computing, parsing, encoding, tokenizing, or serving high-throughput requests.
  2. Choose Python if your application mostly coordinates databases, existing ML frameworks, notebooks, or scripts where developer speed matters more than runtime efficiency.
  3. Choose both if you want the strongest practical architecture: Python at the product or research layer, Rust in the hot path via PyO3.
If your workload is...Better default
CPU-bound parsing, tokenization, inference serving, or compressionRust
notebooks, glue code, and research iterationPython
CRUD APIs mostly waiting on databases or external APIsPython
Python products with one or two expensive hot pathsPython + Rust via PyO3
memory-constrained edge or serverless workloadsRust

What Are the Real Performance Numbers?

Rust is 10–100x faster than Python for CPU-bound work; the gap narrows to 2–5x for I/O-bound work where both languages spend most of their time waiting on external systems.

BenchmarkPythonRustSpeedup
JSON parsing (large file)~2.5s~0.08s~30x
CSV row processing (10M rows)~45s~0.8s~56x
Cosine similarity (1000-dim, 1M pairs)~120s~1.2s~100x
HTTP request handling (10K req/s)Limited by GILFull multi-core5–20x
String processing (BPE tokenization)~8s~0.15s~50x
Regex matching (large corpus)~12s~0.8s~15x
Fibonacci (n=40, recursive)~35s~0.001s~35,000x
Database query (Postgres, 1K rows)~0.05s~0.04s~1.2x

The last row is the key insight: for database-bound work, both languages wait on the database. The language overhead is irrelevant. Python web APIs that spend 95% of their time on I/O are not meaningfully constrained by Python's speed. The performance argument for Rust is strongest when your code does real CPU work, not when it mostly shuffles data between a database and a JSON response.

Bottom line: Rust is 10–100x faster than Python for CPU-bound work, but for database-bound APIs the gap collapses to ~1.2x. The performance argument for Rust is contingent entirely on whether your code actually does CPU work.


Where Does the Performance Gap Actually Hurt?

The Rust vs Python performance gap matters when your code runs CPU-bound work at scale: tokenization, data processing, inference, encoding, compression, cryptography.

LLM Tokenization

Tokenizing text for an LLM (BPE, WordPiece, SentencePiece) is CPU-bound and runs on every request. At 10,000 requests/second, tokenization in Python would consume all available CPU. This is precisely why Hugging Face Tokenizers is written in Rust; the same Python API, 50–100x faster. The Python code you call is a thin wrapper around the Rust implementation.

DataFrame Operations

Processing 100M rows in Pandas takes minutes. The same operation in Polars (Rust core, using Rayon for parallel processing) takes seconds. For data engineering pipelines processing large datasets, this difference is the difference between a nightly batch job and a real-time pipeline. Polars isn't just "fast Pandas"; it uses a completely different architecture enabled by Rust's ownership model and parallelism primitives.

Inference Serving

An LLM inference server handling 500 concurrent requests needs to tokenize, queue, process, and stream tokens; all without the GIL blocking parallelism. Python's GIL means only one request can run Python code at a time. Rust serves all 500 concurrently using async tasks, without the GIL bottleneck.

Where It Does Not Matter

  • CRUD APIs with database I/O: the bottleneck is the database, not the language
  • Data science exploration in Jupyter: development speed matters more than execution speed
  • Glue code, automation, scripts: the code runs once or infrequently; performance is irrelevant
  • ML model training: PyTorch CUDA kernels are already in C++/CUDA; Python overhead during training is minimal compared to GPU time
  • Webhook handlers and event-driven workloads: if you're doing < 1,000 req/s, Python is almost certainly fast enough

Bottom line: The performance gap matters for tokenization, data processing, inference serving, and cryptography at scale. For CRUD APIs, scripts, and ML training, Python's speed is not the bottleneck and the case for Rust evaporates.


Thinking about making the switch to Rust?

See if your background fits — a 2-minute check.

How Does PyO3 Bridge Python and Rust?

PyO3 lets you write performance-critical code in Rust and call it from Python with normal Python function syntax, keeping Python's ecosystem while eliminating its performance bottlenecks in the hot path.

# Python code: calls into Rust transparently
import my_fast_lib
 
# This runs in Rust, returning to Python when done
result = my_fast_lib.process_batch(texts)  # 50x faster than pure Python
// Rust code: exposed to Python via PyO3
use pyo3::prelude::*;
use rayon::prelude::*;
 
#[pyfunction]
fn process_batch(py: Python, texts: Vec<String>) -> PyResult<Vec<usize>> {
    py.allow_threads(|| {          // release GIL: use all cores
        texts.par_iter()           // Rayon parallel iterator
            .map(|t| t.len())      // your expensive operation
            .collect()
    })
}

This is the architecture behind the most performant Python libraries in production today:

  • Polars: Python DataFrame API, Rust engine using Rayon for parallelism
  • Pydantic v2: Python model API, Rust validation engine
  • Hugging Face Tokenizers: Python tokenizer API, Rust BPE implementation
  • Ruff: Python linter CLI, Rust parser and rule engine

The pattern is consistent: keep Python for developer experience and ecosystem access, push CPU-bound work to Rust. This is not a compromise; it is the optimal architecture when you need both.

If that hybrid path is what interests you, Rust vs Python in 2026 is the broader career framing, while Building RAG Applications in Rust 2026 and Rust for MCP Model Context Protocol Servers show where this Python-plus-Rust pattern becomes commercially useful.


How Do Rust and Python Compare for Web APIs?

For most web APIs, Python (FastAPI) is the practical choice; the 5–10x throughput gap only matters at scale. For high-throughput inference APIs, Axum's memory efficiency and predictable latency justify the switch.

MetricFastAPI (Python)Axum (Rust)
Throughput (simple JSON)~15K req/s~80K–150K req/s
Memory baseline~80MB (Python + deps)~5MB
Cold start2–5 seconds<100ms
p99 latency consistencyVariable (GC)Predictable
Lines of code for a simple APISimilarSimilar
Ecosystem maturityExcellentGood and growing
Development speedFastSlower (learning curve)

For a startup CRUD API processing a few thousand requests per second, FastAPI is usually the right choice; the throughput difference does not matter at that scale, and Python's development speed matters a lot. For a high-throughput LLM inference API processing 50,000+ concurrent requests with strict latency SLAs, Axum is worth the extra complexity. The cold start difference alone matters for serverless deployments: a 5MB Rust binary starts in under 100ms; a Python Lambda with dependencies takes 2–5 seconds.

Bottom line: FastAPI handles ~15K req/s and is the practical choice for most web APIs; Axum handles 80K–150K req/s with a 5MB memory footprint. The switch is only justified when you're operating at a scale where that 5–10x throughput gap actually matters.


What Does the Performance Gap Mean for Memory Usage?

Rust uses 5–10x less memory than Python for equivalent workloads: no Python runtime overhead, no garbage collector, no reference counting on every object.

A minimal Python process loaded with typical dependencies (FastAPI, SQLAlchemy, Pydantic) uses 80–150MB of RAM before handling a single request. A minimal Axum binary uses 5–15MB.

This difference matters significantly for:

  • Container costs: running 100 Rust services vs 100 Python services on the same Kubernetes cluster can cut memory bill in half
  • Serverless: Lambda charges for memory allocated; smaller Rust functions cost less per invocation
  • Edge compute: Cloudflare Workers and Fastly Compute@Edge have strict memory limits; Rust fits; Python often does not
  • Embedded systems: Python simply cannot run on microcontrollers; Rust can run on devices with 64KB of RAM

For companies running thousands of service instances, the memory efficiency of Rust is not an academic advantage; it shows up directly in infrastructure costs.


Is Python Getting Faster? Will It Close the Gap?

Python is getting incrementally faster, but the structural gap with compiled Rust is not closing. The GIL, interpreted execution, and dynamic typing are architectural, not implementation bugs.

Python is improving: PyPy, Cython, and CPython's own optimizations have moved the baseline. Python 3.12 introduced meaningful speedups (10–15% on some benchmarks). Python 3.13's free-threaded mode removes the GIL experimentally, which helps multi-threaded CPU workloads.

But consider: even if Python doubled in speed overnight, Rust would still be 5–50x faster on CPU-bound work. The gap is not measured in percentage points; it is measured in orders of magnitude. The interpreted dispatch overhead, the dynamic typing costs, and the GC pause risk are all inherent to CPython's architecture.

The honest answer: Python will get faster, but Rust's performance advantage is structural and will remain for the foreseeable future. The practical implication is that Rust will remain the language of choice for performance-critical infrastructure, and PyO3 will continue to be the bridge for teams that need Python's ecosystem.


What Are Common Misconceptions About Rust vs Python Performance?

Most performance comparisons get the conclusion wrong because they ask the wrong question. They ask "which is faster?" rather than "where does the speed difference actually matter for your system?"

Misconception 1: "NumPy makes Python as fast as Rust." NumPy operations are written in C and FORTRAN. When you call np.dot, you are not running Python. The moment you leave optimized NumPy calls and write a Python loop, you lose all native speed. Rust gives you native speed everywhere, not just inside library boundaries.

Misconception 2: "Just use PyPy and Python is fast enough." PyPy works for pure Python workloads with simple data types. It does not work well with CPython C extensions (NumPy, PyTorch, Pandas use the CPython C API internally). Most production AI/ML Python code cannot run on PyPy for exactly this reason.

Misconception 3: "Python's async makes it as fast as Rust for web APIs." Python's asyncio and uvloop improve I/O concurrency by avoiding blocking threads. But they do not remove the GIL for CPU work, and they do not eliminate the interpreter overhead. An async Python server is better than a synchronous one, but it is still not in the same class as Axum for CPU-intensive workloads.

Misconception 4: "Rewriting everything in Rust is the solution." The 80/20 rule applies strongly: 5% of your code causes 95% of the CPU usage. Profile first. Find the hot path. Rewrite that specific function as a PyO3 extension. Most Python codebases have 2–3 bottlenecks that account for almost all CPU cost. Rewriting those in Rust via PyO3 is the practical approach, not a full rewrite.


What Does This Mean for Your Career?

The Rust-Python relationship is not competition. The highest-value engineers in 2026 understand both and know when to use each.

Python AI engineers who learn Rust open two high-value career paths:

  1. PyO3 engineer: write Rust extensions for Python AI systems; salary $160K–$230K; the exact skill Polars, Pydantic, and HF hired for
  2. Full Rust AI engineer: build inference servers, data pipelines, and infrastructure entirely in Rust; salary $185K–$250K

Neither path requires abandoning Python; Rust knowledge adds to it. The engineers who understand the boundary between when Python is sufficient and when Rust is necessary are precisely the people AI infrastructure companies want most in 2026 [Levels.fyi].

The most direct path: learn Python deeply, build production AI systems with it, then learn Rust by rewriting a bottleneck function with PyO3. That first PyO3 extension is the bridge between the two ecosystems and the start of a differentiated career path.

If you want to make that bridge concrete, the next best reads are Rust Developer Salary USA 2026: Complete Guide, Best Rust Learning Path 2026: From Beginner to Hired, and How Long Does It Take to Learn Rust?. They answer the ROI, learning sequence, and timeline questions that usually come immediately after the performance question.

Bottom line: the highest-value move is rarely “leave Python for Rust.” It is usually “keep Python where it is strong and add Rust where it creates clear performance or systems leverage.”


Frequently Asked Questions

Python is getting faster; PyPy, Cython, and CPython's own optimizations have improved performance. Python 3.12 and 3.13 include measurable speedups. But the GIL and interpreted nature mean the gap with compiled Rust is structural, not a matter of optimization effort. Rust will remain 10–50x faster for CPU-bound work for the foreseeable future.

Probably not entirely. Profile first: find the CPU bottleneck (there usually is one specific function). Rewrite that function as a PyO3 extension. The 80/20 rule applies aggressively; 5% of the code causes 95% of the CPU usage. Rewrite that 5% in Rust, keep the other 95% in Python.

Training runs PyTorch CUDA kernels, which are already written in C++/CUDA. Python overhead during training is minimal; the GPU is the bottleneck, not Python. Rust does not help with training. It helps with data preprocessing, tokenization, and inference serving; not the training loop itself.

Yes; NumPy uses BLAS/LAPACK C libraries for matrix operations. Rust can use the same libraries, or implement SIMD-optimized operations directly. The ndarray crate provides NumPy-like array operations. For specific array workloads, Rust can match or exceed NumPy performance.

PyO3 is a Rust crate that provides bindings between Rust and Python. It lets you write a Rust function decorated with #[pyfunction], compile it to a shared library, and import it from Python like a normal module. The setup requires maturin (the build tool) and basic Rust knowledge. A working PyO3 extension can be built in a day if you know Rust; it is not a research project.

A minimal FastAPI application with common dependencies uses 80–150MB of RAM. A minimal Axum binary uses 5–15MB. At 100 service replicas, that is roughly 7.5GB saved on Python vs 500MB on Rust; a significant Kubernetes memory budget difference. The savings are largest in serverless environments where you pay per MB-second of allocation.

Yes. Hugging Face Tokenizers processes billions of tokenization requests daily in Rust. Polars powers data pipelines at major data engineering teams. Several LLM serving frameworks (candle, llm.rs) are being built in pure Rust. The AI infrastructure layer; tokenization, serving, preprocessing; is increasingly Rust-first.

When your service is I/O-bound. A typical web API that reads from a database, maybe processes a small amount of data, and returns a JSON response is bottlenecked by the database; not by Python's interpretation overhead. FastAPI on Python is genuinely fast enough for the majority of web API use cases up to several thousand requests per second.


How Should You Start Bridging Python and Rust in Practice?

Start with maturin, build one tiny PyO3 function, and prove the workflow on a real bottleneck before you redesign anything bigger.

The practical path for a Python developer who wants to add Rust to their toolkit:

  1. Install maturin: pip install maturin and cargo install maturin. This is the build tool that compiles your Rust code and packages it as a Python-importable .so library.
  2. Create a new project: maturin init --bindings pyo3. This scaffolds a minimal project with the Cargo.toml and lib.rs already configured.
  3. Write one function: pick the slowest function in your Python codebase; the one cProfile or py-spy identifies as the hottest. Rewrite that one function in Rust with #[pyfunction].
  4. Benchmark: compare the Python version against the Rust version. The result will motivate the next step.

Most Python developers who go through this exercise once are hooked. The performance improvement is immediate and measurable. Hugging Face, Pydantic, and Polars all started this way; a specific bottleneck that Python could not solve, solved with Rust, then expanded from there.


Sources

Keep Reading


  • Ownership: How Rust's memory model eliminates GC pauses for consistent performance
  • Vec: Rust's contiguous array: cache-friendly and faster than Python lists
  • Iterator: Zero-cost lazy iteration: no intermediate allocations
  • Rayon: Parallel iteration across all CPU cores: what Python's GIL prevents
  • Async/Await: Rust async vs Python asyncio: same concept, no GIL overhead
  • Struct: Stack-allocated structs with no object overhead vs Python classes

Ready to Land a $80-120k Rust Job?