【问题标题】:Why enum value binding in Rust is so slow?为什么 Rust 中的枚举值绑定这么慢?
【发布时间】: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


【解决方案1】:

查看程序集,您的第一个循环被完全优化为单个 mov 10000000 指令(即编译器执行与 sum += EXAMPLES 等效的操作),而第二个循环则没有。我不知道为什么第二个循环没有进行大量的持续优化。

【讨论】:

    【解决方案2】:

    正如预期的那样,我认为性能没有差异。

    $ ./test
    enum without fields func call sum: 10000000 at 307.543596ms
    enum with field func call sum: 10000000 at 312.196195ms
    
    $ rustc --version
    rustc 1.43.1 (8d69840ab 2020-05-04)
    
    $ uname -a
    Darwin Windhund.local 18.7.0 Darwin Kernel Version 18.7.0: Mon Feb 10 21:08:45 PST 2020; root:xnu-4903.278.28~1/RELEASE_X86_64 x86_64 i386 MacBookPro15,2 Darwin
    

    一个问题可能是使用简单的“挂钟”时间进行基准测试。这个简单的时间计算很容易受到任何可能消耗资源的运行的影响。防病毒,网络浏览器,任何程序。请改用benchmark tests

    【讨论】:

      猜你喜欢
      • 2019-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多