为什么我执行阵列反转的Rust程序要比同等的Go程序慢?

时间:2018-07-05 11:41:22

标签: go rust

我正在初始化一个数组,然后多次反转以查看性能。

我想了解我是否编写了无法比较的代码,或者Rust真的很糟糕以至于花费了很多时间?

以下是Rust的构建和计时过程:

rustc main.rs
time ./main

这会继续运行。真令人惊讶

铁锈

fn reverse(mylist: &mut Vec<u16>) {
    let length = mylist.len();

    let mid_length = length / 2;

    for number in 0..mid_length {
        let mut a = mylist[number];
        let mut b = mylist[length - number - 1];

        mylist[number] = b;

        mylist[length - number - 1] = a;
    }
}

fn main() {
    let array_size = 100000;

    let iterations = 100000;

    let mut v = vec![0u16; array_size];

    for _ in 0..iterations {
        reverse(&mut v);
    }
}

开始

Go代码完全可以完成Rust代码在上面的工作。需要注意的重要一点是Go具有垃圾收集功能,而Rust则没有。令人惊讶的是,Go在不到6秒的时间内完成了工作:

go build main.go
time ./main 100000 100000

real    0m5.932s
user    0m5.928s
sys 0m0.004s

开始

package main

import (
    "os"
    "strconv"
)

func reverse(mylist []int) []int {

    length := len(mylist)
    half := int(length / 2)

    for i := 0; i < half; i++ {

        mylist[i], mylist[length-i-1] = mylist[length-i-1], mylist[i]

    }   

    return mylist

}

func main() {

    array_size, _ := strconv.Atoi(os.Args[1])
    iterations, _ := strconv.Atoi(os.Args[2])

    mylist := make([]int, array_size)

    for i := 0; i < iterations; i++ {
        reverse(mylist)

    }

}

1 个答案:

答案 0 :(得分:5)

默认情况下,version: "3" services: h2o-start: image: milanpanic2/h2o-start build: context: ./h2o-start ports: - "54321:54321" - "54322:54322" volumes: - "home/data" model-generator: image: milanpanic2/model-generator build: context: ./model-generator ports: - "8080:8080" depends_on: - "h2o-start" volumes: - "csvdata:/var/my-data" volumes: csvdata: (和rustc)在调试模式下编译。它被认为是最有用的默认值,因为它是开发过程中最常编译的一个。

调试模式(尤其是在您的代码中)包括很多检查:每次对cargo的访问都受到边界检查的保护。

相反,出于基准测试的目的,您希望进行优化编译。如果直接使用mylist[..],这就像传递rustc标志一样简单。


如@ljerdz所述,有一种[T]::reverse方法,它比您的实现效率更高,因为它在内部使用-O来进行边界检查。

在操场上快速查看并不会发现您的unsafereverse之间有什么奇异的区别;优化器已经足够聪明,可以取消边界检查。

不幸的是,它不够智能以消除循环,可能是因为它没有意识到Vec::reverse__rust_alloc_zeroed是内存分配/释放例程,并且没有明显的副作用。