为什么在Sw中交换[] float64的元素比在Rust中交换Vec <f64>的元素更快?

-6 performance go rust llvm-codegen

我有两个(相当于?)程序,一个在另一个在Rust中.平均执行时间是:

  • 去~169ms
  • 生锈~201ms

package main

import (
    "fmt"
    "time"
)

func main() {
    work := []float64{0.00, 1.00}
    start := time.Now()

    for i := 0; i < 100000000; i++ {
        work[0], work[1] = work[1], work[0]
    }

    elapsed := time.Since(start)
    fmt.Println("Execution time: ", elapsed)
}
Run Code Online (Sandbox Code Playgroud)

我编译了 --release

use std::time::Instant;

fn main() {
    let mut work: Vec<f64> = Vec::new();
    work.push(0.00);
    work.push(1.00);

    let now = Instant::now();

    for _x in 1..100000000 {
        work.swap(0, 1); 
    }

    let elapsed = now.elapsed();
    println!("Execution time: {:?}", elapsed);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Rust的性能是否低于Go?Rust程序是否可以用惯用的方式编写,以便更快地执行?

Luk*_*odt 9

Rust程序是否可以用惯用的方式编写,以便更快地执行?

是.要创建包含少量元素的向量,请使用以下vec![]宏:

let mut work: Vec<f64> = vec![0.0, 1.0];    

for _x in 1..100000000 {
    work.swap(0, 1); 
}
Run Code Online (Sandbox Code Playgroud)

那么这段代码更快吗?是.看看生成的程序集:

example::main:
  mov eax, 99999999
.LBB0_1:
  add eax, -11
  jne .LBB0_1
  ret
Run Code Online (Sandbox Code Playgroud)

在我的电脑上,这比原始代码快30倍.

为什么程序集仍然包含无效的循环?为什么编译器不能看到两个pushes是相同的vec![0.0, 1.0]?两个非常好的问题都可能指向LLVM或Rust编译器中的缺陷.

然而,遗憾的是,从微观基准中获得的信息并不多.基准测试很难,就像真的很难.甚至专业人士都有很多陷阱.在您的情况下,基准测试在几个方面存在缺陷.首先,你永远不会观察到矢量的内容(它从未使用过).这就是为什么一个好的编译器可以删除所有甚至触及向量的代码(正如Rust编译器在上面所做的那样).所以这不好.

除此之外,这与任何真正的性能关键代码都不相似.即使稍后会观察到矢量,交换奇数次也等于单次交换.所以除非你想看看优化器能否理解这个交换规则,遗憾的是你的基准测试并不是真的有用.

  • @Kyle如果你有一个比预期更慢的冒泡排序的更完整的例子,你应该打开另一个问题 (3认同)