【发布时间】:2020-05-20 20:57:42
【问题描述】:
我目前正在学习 Rust,因为我想在需要非常高性能的项目中使用它。我最初爱上了枚举,但后来我开始评估它们的性能,我发现了一些让我难以置信的东西。这是一个例子:
use std::time::{Instant};
pub enum MyEnum<'a> {
V1,
V2(&'a MyEnum<'a>),
V3,
}
impl MyEnum<'_> {
pub fn eval(&self) -> i64 {
match self {
MyEnum::V1 => 1,
MyEnum::V2(_) => 2,
MyEnum::V3 => 3,
}
}
pub fn eval2(&self) -> i64 {
match self {
MyEnum::V1 => 1,
MyEnum::V2(a) => a.eval2(),
MyEnum::V3 => 3,
}
}
}
fn main() {
const EXAMPLES: usize = 10000000;
let en = MyEnum::V1{};
let start = Instant::now();
let mut sum = 0;
for _ in 0..EXAMPLES {
sum += en.eval()
}
println!("enum without fields func call sum: {} at {:?}", sum, start.elapsed());
let start = Instant::now();
let mut sum = 0;
for _ in 0..EXAMPLES {
sum += en.eval2()
}
println!("enum with field func call sum: {} at {:?}", sum, start.elapsed());
}
我得到的结果:
enum without fields func call sum: 10000000 at 100ns
enum with field func call sum: 10000000 at 6.3425ms
eval 函数应该为 V1 枚举执行与 eval2 完全相同的指令,但它的工作速度大约慢了 60 倍。为什么会这样?
【问题讨论】:
-
欢迎来到 Stack Overflow!很难回答您的问题,因为它不包含minimal reproducible example。我们无法确切地告诉您如何运行此代码。请edit您的问题包括附加信息。谢谢!
-
另外,您的第二个函数执行递归调用,这与第一个函数完全不同。为什么你认为这些应该完全一样?
-
第一个函数最有可能优化为
return discriminant + 1;。第二个函数需要一个分支。 -
此外,在第一个函数中,编译器内联函数调用,并且足够聪明地将循环转换为单个
sum += EXAMPLES。这个基准被打破了。 -
提示:100ns 内的 1000 万次循环迭代应该会告诉您基准测试有问题,因为单个 CPU 周期大约是 1/3 纳秒。
标签: performance enums rust