Performance Comparison: Python vs Rust for Fibonacci Calculation

· 3min · Pragmatic AI Labs

Performance Comparison: Python vs Rust for Fibonacci Calculation

When it comes to computational performance, choosing the right programming language can make a significant difference. This post explores a practical comparison between Python and Rust implementations of the Fibonacci sequence calculator, complete with instrumentation for precise performance measurements.

graph TD;
A[Start] --> B[End];

Project Structure

graph TD;
A[Project Root] --> B[Python Implementation];
A --> C[Rust Implementation];
A --> D[Profiling Script];
B --> E[fib2.py];
C --> F[fib2.rs];
D --> G[profiler.sh];
G --> H[performance_metrics.csv];

Performance Overview

gantt
title Performance Comparison: Python vs Rust (Fibonacci 40)
dateFormat X
axisFormat %s

section Python
7.47 seconds: 0, 7.47

section Rust
0.174 seconds: 0, 0.174

Code Implementation

Let's look at our baseline implementations. All code is available on Codeberg.

Python Implementation (fib2.py)

import time

def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

start_time = time.time()
fibonacci(40)
end_time = time.time()
execution_time = end_time - start_time
print(execution_time)

Rust Implementation (fib2.rs)

use std::time::Instant;

fn fibonacci(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n - 1) + fibonacci(n - 2),
    }
}

fn main() {
    let start = Instant::now();
    fibonacci(40);
    let duration = start.elapsed();
    println!("{:.4}", duration.as_secs_f64());
}

Profiling Script (profiler.sh)

#!/bin/bash

# File to store performance metrics
output_file="performance_metrics.csv"

# Create the CSV file with headers if it doesn't exist
if [ ! -f "$output_file" ]; then
    echo "Timestamp,Language,ExecutionTime" > "$output_file"
fi

# Number of iterations to run
iterations=10

# Function to run Python script and log execution time
run_python() {
    start_time=$(date +%Y-%m-%dT%H:%M:%S.%3N)
    execution_time=$(python3 fib2.py)
    echo "$start_time,Python,$execution_time" >> "$output_file"
}

# Function to run Rust script and log execution time
run_rust() {
    start_time=$(date +%Y-%m-%dT%H:%M:%S.%3N)
    execution_time=$(./fib2)
    echo "$start_time,Rust,$execution_time" >> "$output_file"
}

# Run Python and Rust scripts for specified iterations
for ((i=1; i<=$iterations; i++)); do
    echo "Running iteration $i..."
    run_python
    run_rust
done

echo "Performance metrics saved to $output_file"

Results Analysis

graph TD;
subgraph Python[Python Execution Times]
A[Run 1: 7.29s] --> B[Run 2: 7.38s];
B --> C[Run 3: 7.34s];
C --> D[Run 4: 7.41s];
D --> E[Run 5: 7.33s];
end

subgraph Rust[Rust Execution Times]
F[Run 1: 0.174s] --> G[Run 2: 0.173s];
G --> H[Run 3: 0.174s];
H --> I[Run 4: 0.173s];
I --> J[Run 5: 0.175s];
end

Key Findings

graph LR;
A[Performance Results] --> B[Python ~7.47s];
A --> C[Rust ~0.174s];
B --> D[Standard Library];
C --> E[Optimized Binary];
D --> F[CPU Bound];
E --> G[43x Faster];

Performance Analysis Setup

The experiment uses a bash-based profiler to ensure consistent timing measurements across both languages. This centralized approach provides several benefits:

  • Unified timestamp generation
  • Consistent metrics collection
  • Language-agnostic measurement system
  • Data format suitable for further analysis

Implementation Details

Both implementations calculate the 40th Fibonacci number using recursive approaches. The profiler executes each implementation 10 times and records:

  • Timestamp of execution
  • Programming language used
  • Execution duration in seconds

Raw performance data sample:

2024-12-30T06:11:39.250,Python,7.291918516159058
2024-12-30T06:11:46.559,Rust,0.1744
2024-12-30T06:11:46.736,Python,7.383427619934082
2024-12-30T06:11:54.137,Rust,0.1739

Optimization Opportunities

For Python:

  • Replace recursion with dynamic programming
  • Consider using PyPy for improved performance
  • Implement memoization
  • Explore Numba or Cython for critical sections

For Rust:

  • Use release mode compilation (cargo build --release)
  • Consider using u64 for larger numbers
  • Explore const generics for compile-time evaluation
  • Implement iterative solution for better memory usage

Conclusion

This performance comparison demonstrates the significant advantages of Rust for computationally intensive tasks, while also highlighting the importance of proper instrumentation and measurement in performance analysis. Even with unoptimized recursive implementations, the performance difference is substantial.


Want expert ML/AI training? Visit paiml.com

For hands-on courses: DS500 Platform

Based on this article's content, here are some courses that might interest you:

  1. AWS Advanced AI Engineering (1 week) Production LLM architecture patterns using Rust, AWS, and Bedrock.

  2. Rust GUI Development for Linux (4 weeks) Learn to create native Linux GUI applications using Rust and popular frameworks like Iced, GTK, and EGUI. Build practical projects while mastering Rust GUI development fundamentals.

  3. Python Essentials for MLOps (5 weeks) Learn essential Python programming skills required for modern Machine Learning Operations (MLOps). Master fundamentals through advanced concepts with hands-on practice in data science libraries and ML application development.

  4. Deno TypeScript Development (2 weeks) Build secure, modern TypeScript applications with Deno runtime

  5. Rust-Powered AWS Serverless (4 weeks) Learn to develop serverless applications on AWS using Rust and AWS Lambda. Master the fundamentals of serverless architecture while building practical applications and understanding performance optimizations.

Learn more at Pragmatic AI Labs