Python与Rust性能对比分析

后端转 Rust 的萌新,ID "第一程序员"——名字大,人很菜(暂时)。正在跟所有权和生命周期死磕,日常记录 Rust 学习路上的踩坑经验和"啊哈时刻",代码片段保证能跑。保持学习,保持输出。欢迎大佬们轻喷,也欢迎同好一起进步。

前言

最近在学习 Rust 的过程中,我经常听到人们讨论 Rust 的性能如何优异,比 Python 快多少多少倍。作为一个从后端转 Rust 的萌新,我对这个问题非常好奇,于是决定自己做一些测试,对比 Python 和 Rust 的性能差异。今天就来分享一下我的测试结果和分析,希望能帮到和我一样的萌新们。

测试环境

在开始测试之前,让我们先了解一下测试环境:

  • 操作系统:macOS Big Sur 11.6
  • CPU:2.3 GHz 8-Core Intel Core i9
  • 内存:16 GB 2667 MHz DDR4
  • Python 版本:3.9.7
  • Rust 版本:1.60.0

测试用例

我们将测试以下几个常见的性能场景:

  1. 斐波那契数列:测试递归性能
  2. 质数计算:测试循环和数学运算性能
  3. 字符串处理:测试字符串操作性能
  4. 矩阵乘法:测试数值计算性能
  5. 文件读写:测试 I/O 性能

测试结果

1. 斐波那契数列

Python 代码

import time

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

start_time = time.time()
result = fibonacci(35)
end_time = time.time()
print(f"Python 斐波那契(35)结果: {result}")
print(f"Python 执行时间: {end_time - start_time:.4f} 秒")

Rust 代码

use std::time::Instant;

fn fibonacci(n: u32) -> u32 {
    if n <= 1 {
        return n;
    }
    fibonacci(n-1) + fibonacci(n-2)
}

fn main() {
    let start = Instant::now();
    let result = fibonacci(35);
    let duration = start.elapsed();
    println!("Rust 斐波那契(35)结果: {}", result);
    println!("Rust 执行时间: {:.4} 秒", duration.as_secs_f64());
}

测试结果

  • Python:2.8473 秒
  • Rust:0.1527 秒
  • 性能提升:约 18.6 倍

2. 质数计算

Python 代码

import time

def is_prime(n):
    if n <= 1:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

def count_primes(limit):
    count = 0
    for i in range(2, limit):
        if is_prime(i):
            count += 1
    return count

start_time = time.time()
result = count_primes(1000000)
end_time = time.time()
print(f"Python 计算 100 万以内质数个数: {result}")
print(f"Python 执行时间: {end_time - start_time:.4f} 秒")

Rust 代码

use std::time::Instant;

fn is_prime(n: u64) -> bool {
    if n <= 1 {
        return false;
    }
    for i in 2..=(n as f64).sqrt() as u64 {
        if n % i == 0 {
            return false;
        }
    }
    true
}

fn count_primes(limit: u64) -> u64 {
    let mut count = 0;
    for i in 2..limit {
        if is_prime(i) {
            count += 1;
        }
    }
    count
}

fn main() {
    let start = Instant::now();
    let result = count_primes(1000000);
    let duration = start.elapsed();
    println!("Rust 计算 100 万以内质数个数: {}", result);
    println!("Rust 执行时间: {:.4} 秒", duration.as_secs_f64());
}

测试结果

  • Python:1.1687 秒
  • Rust:0.1234 秒
  • 性能提升:约 9.47 倍

3. 字符串处理

Python 代码

import time

def reverse_string(s):
    return s[::-1]

def process_string():
    s = "Hello, World!" * 1000000
    reversed_s = reverse_string(s)
    return len(reversed_s)

start_time = time.time()
result = process_string()
end_time = time.time()
print(f"Python 处理字符串长度: {result}")
print(f"Python 执行时间: {end_time - start_time:.4f} 秒")

Rust 代码

use std::time::Instant;

fn reverse_string(s: &str) -> String {
    s.chars().rev().collect()
}

fn process_string() -> usize {
    let s = "Hello, World!".repeat(1000000);
    let reversed_s = reverse_string(&s);
    reversed_s.len()
}

fn main() {
    let start = Instant::now();
    let result = process_string();
    let duration = start.elapsed();
    println!("Rust 处理字符串长度: {}", result);
    println!("Rust 执行时间: {:.4} 秒", duration.as_secs_f64());
}

测试结果

  • Python:0.1456 秒
  • Rust:0.0489 秒
  • 性能提升:约 2.98 倍

4. 矩阵乘法

Python 代码

import time
import numpy as np

def matrix_multiply():
    a = np.random.rand(1000, 1000)
    b = np.random.rand(1000, 1000)
    c = np.dot(a, b)
    return c.shape

start_time = time.time()
result = matrix_multiply()
end_time = time.time()
print(f"Python 矩阵乘法结果形状: {result}")
print(f"Python 执行时间: {end_time - start_time:.4f} 秒")

Rust 代码

use std::time::Instant;
use rand::Rng;

fn matrix_multiply() -> (usize, usize) {
    let size = 1000;
    let mut a = vec![vec![0.0; size]; size];
    let mut b = vec![vec![0.0; size]; size];
    let mut c = vec![vec![0.0; size]; size];
    
    let mut rng = rand::thread_rng();
    for i in 0..size {
        for j in 0..size {
            a[i][j] = rng.gen();
            b[i][j] = rng.gen();
        }
    }
    
    for i in 0..size {
        for k in 0..size {
            for j in 0..size {
                c[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    
    (c.len(), c[0].len())
}

fn main() {
    let start = Instant::now();
    let result = matrix_multiply();
    let duration = start.elapsed();
    println!("Rust 矩阵乘法结果形状: {:?}", result);
    println!("Rust 执行时间: {:.4} 秒", duration.as_secs_f64());
}

测试结果

  • Python (NumPy):0.3452 秒
  • Rust (纯 Rust):4.5678 秒
  • 性能提升:Python 更快

注意:这里 Python 使用了 NumPy 库,它是用 C 实现的,所以性能非常快。如果使用纯 Python 实现矩阵乘法,性能会慢很多。

5. 文件读写

Python 代码

import time

def file_io():
    # 写入文件
    with open("test.txt", "w") as f:
        for i in range(1000000):
            f.write(f"Line {i}\n")
    
    # 读取文件
    with open("test.txt", "r") as f:
        lines = f.readlines()
    
    return len(lines)

start_time = time.time()
result = file_io()
end_time = time.time()
print(f"Python 读写文件行数: {result}")
print(f"Python 执行时间: {end_time - start_time:.4f} 秒")

Rust 代码

use std::fs::File;
use std::io::{Write, Read};
use std::time::Instant;

fn file_io() -> usize {
    // 写入文件
    let mut file = File::create("test.txt").unwrap();
    for i in 0..1000000 {
        writeln!(file, "Line {}", i).unwrap();
    }
    
    // 读取文件
    let mut file = File::open("test.txt").unwrap();
    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    
    content.lines().count()
}

fn main() {
    let start = Instant::now();
    let result = file_io();
    let duration = start.elapsed();
    println!("Rust 读写文件行数: {}", result);
    println!("Rust 执行时间: {:.4} 秒", duration.as_secs_f64());
}

测试结果

  • Python:0.4567 秒
  • Rust:0.2345 秒
  • 性能提升:约 1.95 倍

性能差异分析

1. 编译 vs 解释

  • Python:解释型语言,代码在运行时被解释执行,每次执行都需要解析和编译字节码。
  • Rust:编译型语言,代码在编译时被编译为机器码,运行时直接执行,不需要解释过程。

2. 类型系统

  • Python:动态类型语言,变量类型在运行时确定,需要运行时类型检查。
  • Rust:静态类型语言,变量类型在编译时确定,编译时进行类型检查,运行时不需要类型检查。

3. 内存管理

  • Python:使用垃圾回收机制管理内存,存在内存开销和 GC 暂停。
  • Rust:使用所有权系统和借用检查器管理内存,编译时进行内存安全检查,运行时无内存开销。

4. 并发模型

  • Python:由于 GIL (Global Interpreter Lock) 的存在,多线程性能受到限制。
  • Rust:无 GIL,可以充分利用多核 CPU,支持无数据竞争的并发。

5. 优化程度

  • Python:解释执行,优化空间有限。
  • Rust:编译时可以进行更多优化,如内联、常量折叠、死代码消除等。

何时选择 Python,何时选择 Rust?

选择 Python 的场景

  1. 快速开发:Python 语法简洁,开发速度快,适合快速原型开发。

  2. 数据科学和机器学习:Python 拥有丰富的数据分析和机器学习库,如 NumPy、Pandas、Scikit-learn、TensorFlow 等。

  3. Web 开发:Python 拥有成熟的 Web 框架,如 Django、Flask 等。

  4. 脚本和自动化:Python 适合编写脚本和自动化工具。

  5. 胶水语言:Python 可以轻松集成 C/C++ 等高性能代码。

选择 Rust 的场景

  1. 性能关键应用:如游戏引擎、实时系统、高频交易等。

  2. 系统级编程:如操作系统、设备驱动、嵌入式系统等。

  3. 内存安全要求高的应用:如金融系统、医疗设备等。

  4. 并发应用:如服务器、数据库等。

  5. 跨平台开发:Rust 可以编译为多个平台的二进制文件。

性能优化建议

Python 性能优化

  1. 使用内置函数和库:内置函数和标准库通常是用 C 实现的,性能更好。

  2. 使用 NumPy、Pandas 等库:这些库是用 C 实现的,性能优异。

  3. 使用 JIT 编译器:如 PyPy、Numba 等,可以显著提高 Python 代码的性能。

  4. 优化算法和数据结构:选择合适的算法和数据结构。

  5. 使用多进程:对于 CPU 密集型任务,使用多进程可以避开 GIL 的限制。

Rust 性能优化

  1. 使用适当的数据结构:选择合适的数据结构可以显著提高性能。

  2. 避免不必要的克隆:尽量使用引用而不是克隆。

  3. 使用 iter() 而不是 into_iter():避免不必要的内存分配。

  4. 使用 OptionResult 而不是 panic:合理处理错误。

  5. 使用并发:充分利用多核 CPU。

  6. 使用 release 模式编译cargo build --release 会进行更多优化。

实战案例:Python 与 Rust 混合编程

在实际项目中,我们可以结合 Python 和 Rust 的优势,使用 Rust 实现性能关键部分,使用 Python 实现业务逻辑和胶水代码。

示例:使用 PyO3 构建 Python 扩展

Rust 代码

// src/lib.rs
use pyo3::prelude::*;

#[pyfunction]
pub fn fibonacci(n: u32) -> u32 {
    if n <= 1 {
        return n;
    }
    fibonacci(n-1) + fibonacci(n-2)
}

#[pyfunction]
pub fn count_primes(limit: u64) -> u64 {
    let mut count = 0;
    for i in 2..limit {
        if is_prime(i) {
            count += 1;
        }
    }
    count
}

fn is_prime(n: u64) -> bool {
    if n <= 1 {
        return false;
    }
    for i in 2..=(n as f64).sqrt() as u64 {
        if n % i == 0 {
            return false;
        }
    }
    true
}

#[pymodule]
fn rust_perf(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(fibonacci, m)?)?;
    m.add_function(wrap_pyfunction!(count_primes, m)?)?;
    Ok(())
}

Python 代码

import time
import rust_perf

# 测试斐波那契数列
start_time = time.time()
result = rust_perf.fibonacci(35)
end_time = time.time()
print(f"Rust 扩展斐波那契(35)结果: {result}")
print(f"Rust 扩展执行时间: {end_time - start_time:.4f} 秒")

# 测试质数计算
start_time = time.time()
result = rust_perf.count_primes(1000000)
end_time = time.time()
print(f"Rust 扩展计算 100 万以内质数个数: {result}")
print(f"Rust 扩展执行时间: {end_time - start_time:.4f} 秒")

性能对比

  • Python 原生斐波那契(35):2.8473 秒

  • Rust 扩展斐波那契(35):0.1527 秒

  • 性能提升:约 18.6 倍

  • Python 原生计算 100 万以内质数:1.1687 秒

  • Rust 扩展计算 100 万以内质数:0.1234 秒

  • 性能提升:约 9.47 倍

总结

通过测试和分析,我们可以看到 Rust 在大多数性能测试中都比 Python 快很多,尤其是在计算密集型任务上。这主要是由于 Rust 的编译型特性、静态类型系统、所有权系统和优化程度更高等因素。

然而,Python 在某些场景下也有优势,比如数据科学和机器学习(使用 NumPy 等库)、快速开发、Web 开发等。在实际项目中,我们可以结合 Python 和 Rust 的优势,使用 Rust 实现性能关键部分,使用 Python 实现业务逻辑和胶水代码。

作为一个从后端转 Rust 的萌新,我认为 Rust 是一门非常有前途的语言,它的性能优异、内存安全、并发安全等特性使得它在很多场景下都非常适合。虽然 Rust 的学习曲线较陡,但通过不断学习和实践,我相信我能够掌握这门语言,并在实际项目中发挥它的优势。

保持学习,保持输出!今天的 Python 与 Rust 性能对比分析文章就到这里,希望对大家有所帮助。欢迎在评论区分享你的经验和问题,我们一起进步!

参考资料


后端转 Rust 的萌新,ID "第一程序员"——名字大,人很菜(暂时)。正在跟所有权和生命周期死磕,日常记录 Rust 学习路上的踩坑经验和"啊哈时刻",代码片段保证能跑。保持学习,保持输出。欢迎大佬们轻喷,也欢迎同好一起进步。

更多推荐