Python与Rust性能对比分析
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
测试用例
我们将测试以下几个常见的性能场景:
- 斐波那契数列:测试递归性能
- 质数计算:测试循环和数学运算性能
- 字符串处理:测试字符串操作性能
- 矩阵乘法:测试数值计算性能
- 文件读写:测试 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 的场景
-
快速开发:Python 语法简洁,开发速度快,适合快速原型开发。
-
数据科学和机器学习:Python 拥有丰富的数据分析和机器学习库,如 NumPy、Pandas、Scikit-learn、TensorFlow 等。
-
Web 开发:Python 拥有成熟的 Web 框架,如 Django、Flask 等。
-
脚本和自动化:Python 适合编写脚本和自动化工具。
-
胶水语言:Python 可以轻松集成 C/C++ 等高性能代码。
选择 Rust 的场景
-
性能关键应用:如游戏引擎、实时系统、高频交易等。
-
系统级编程:如操作系统、设备驱动、嵌入式系统等。
-
内存安全要求高的应用:如金融系统、医疗设备等。
-
并发应用:如服务器、数据库等。
-
跨平台开发:Rust 可以编译为多个平台的二进制文件。
性能优化建议
Python 性能优化
-
使用内置函数和库:内置函数和标准库通常是用 C 实现的,性能更好。
-
使用 NumPy、Pandas 等库:这些库是用 C 实现的,性能优异。
-
使用 JIT 编译器:如 PyPy、Numba 等,可以显著提高 Python 代码的性能。
-
优化算法和数据结构:选择合适的算法和数据结构。
-
使用多进程:对于 CPU 密集型任务,使用多进程可以避开 GIL 的限制。
Rust 性能优化
-
使用适当的数据结构:选择合适的数据结构可以显著提高性能。
-
避免不必要的克隆:尽量使用引用而不是克隆。
-
使用
iter()而不是into_iter():避免不必要的内存分配。 -
使用
Option和Result而不是 panic:合理处理错误。 -
使用并发:充分利用多核 CPU。
-
使用
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 学习路上的踩坑经验和"啊哈时刻",代码片段保证能跑。保持学习,保持输出。欢迎大佬们轻喷,也欢迎同好一起进步。
更多推荐

所有评论(0)