go - 为什么执行数组反转的 Rust 程序比等效的 Go 程序慢?

标签 go rust

<分区>

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

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

这是 Rust 的构建和计时过程:

rustc main.rs
time ./main

这会一直运行下去。这是令人惊讶的

使用rust

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)

    }

}

最佳答案

默认情况下,rustc(和cargo)在 Debug模式下编译。它被认为是最有用的默认设置,因为它在开发过程中最常编译。

Debug模式,尤其是在您的代码中,包括很多检查:对mylist[..] 的每次访问都受到边界检查等的保护。

相反,出于基准测试目的,您需要进行优化编译。如果直接使用 rustc,这就像传递 -O 标志一样简单。


如@ljerdz 所述,有一个 [T]::reverse方法,它甚至比您的实现更有效,因为它在内部使用 unsafe 来省略边界检查。

不过,快速检查一下 playground,并没有发现您的 reverseVec::reverse 之间有任何奇怪的区别;优化器已经足够聪明,可以忽略边界检查。

不幸的是,它不够聪明,无法省略循环,可能是因为它没有意识到 __rust_alloc_zeroed__rust_dealloc 是内存分配/释放例程,并且没有可观察到的方面-效果。

关于go - 为什么执行数组反转的 Rust 程序比等效的 Go 程序慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51190458/

相关文章:

go - 如何使用 Godep 将我的 Go 应用程序部署到 heroku?

deployment - 无法将示例 GOLang 应用程序部署到 Heroku

rust - 从 Axum IntoResponse 访问请求 header

rust - `*(&' a mut self)` 方法中的生命周期参数是否会混淆 BorrowChecker?

rust - 为什么必须在特征对象引用的集合中指定关联类型?

go - 如何在golang结构中使用bit而不是bool?

http - 池连接每次都连接?

go - 如何使用自定义环境变量 "go build -ldflags"

rust - 编译器(特别是 rustc)真的可以简化三角求和以避免循环吗?如何?

rust - 获取 Rc 后面对象的引用