猿问

为什么我的 Rust 程序比执行相同按位和 I/O 操作的 Go 程序慢 4 倍?

我有一个 Rust 程序,它实现了对 64 位无符号整数的蛮力奇偶校验:


use std::io;

use std::io::BufRead;


fn parity(mut num: u64) -> u8 {

    let mut result: u8 = 0;

    while num > 0 {

        result = result ^ (num & 1) as u8;

        num = num >> 1;

    }

    result

}


fn main() {

    let stdin = io::stdin();

    let mut num: u64;

    let mut it = stdin.lock().lines();

    // skip 1st line with number of test cases

    it.next();

    for line in it {

        num = line.unwrap().parse().unwrap();

        println!("{}", parity(num));

    }

}

当我用包含 1000000 个无符号整数的输入文件提供它时:


$ rustc parity.rs

$ time cat input.txt | ./parity &> /dev/null

cat input.txt  0.00s user 0.02s system 0% cpu 4.178 total

./parity &> /dev/null  3.87s user 0.32s system 99% cpu 4.195 total

这里有一个惊喜 - Go 中实际上相同的程序执行速度提高了 4 倍:


$ go build parity.go

$ time cat input.txt | ./parity &> /dev/null

cat input.txt  0.00s user 0.03s system 3% cpu 0.952 total

./parity &> /dev/null  0.63s user 0.32s system 99% cpu 0.955 total

这是 Go 中的代码:


package main


import (

    "bufio"

    "fmt"

    "os"

    "strconv"

)


func parity(line string) uint64 {

    var parity uint64

    u, err := strconv.ParseUint(line, 10, 64)

    if err != nil {

        panic(err)

    }

    for u > 0 {

        parity ^= u & 1

        u >>= 1

    }

    return parity

}


func main() {

    scanner := bufio.NewScanner(os.Stdin)

    // skip line with number of cases

    if !scanner.Scan() {

        // panic if there's no number of test cases

        panic("missing number of test cases")

    }

    for scanner.Scan() {

        fmt.Println(parity(scanner.Text()))

    }

    if err := scanner.Err(); err != nil {

        fmt.Fprintln(os.Stderr, "reading standard input:", err)

    }

}

版本:


$ rustc --version

rustc 1.7.0

$ go version

go version go1.6 darwin/amd64

输入文件示例,第一行包含文件中输入值的数量:


8

7727369244898783789

2444477357490019411

4038350233697550492

8106226119927945594

1538904728446207070

0

1

18446744073709551615

为什么我编写的 Rust 和 Go 程序在性能上有如此巨大的差异?在这种情况下,我预计 Rust 会比 Go 快一点。我的 Rust 代码做错了吗?


MM们
浏览 160回答 2
2回答

梵蒂冈之花

我认为您没有进行优化编译。尝试$ rustc -O parity.rs

尚方宝剑之说

您的基准不衡量奇偶校验。它测量输入加奇偶校验加输出。例如,在 Go 中,您可以测量scanner.Scan和strconv.ParseUint和fmt.Println以及奇偶校验。这是一个 Go 基准测试,它只测量 1000000 次奇偶校验。parity_test.go:package parityimport (&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "runtime"&nbsp; &nbsp; "testing")func parity(n uint64) uint64 {&nbsp; &nbsp; var parity uint64&nbsp; &nbsp; for n > 0 {&nbsp; &nbsp; &nbsp; &nbsp; parity ^= n & 1&nbsp; &nbsp; &nbsp; &nbsp; n >>= 1&nbsp; &nbsp; }&nbsp; &nbsp; return parity}func init() { runtime.GOMAXPROCS(1) }// Benchmark 1000000 parity checks.func BenchmarkParity1000000(b *testing.B) {&nbsp; &nbsp; n := make([]uint64, 1000000)&nbsp; &nbsp; for i := range n {&nbsp; &nbsp; &nbsp; &nbsp; r := uint64(rand.Uint32())&nbsp; &nbsp; &nbsp; &nbsp; n[i] = (r << 32) | r&nbsp; &nbsp; }&nbsp; &nbsp; p := parity(42)&nbsp; &nbsp; b.ResetTimer()&nbsp; &nbsp; for i := 0; i < b.N; i++ {&nbsp; &nbsp; &nbsp; &nbsp; for _, n := range n {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p = parity(n)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; b.StopTimer()&nbsp; &nbsp; _ = p}输出:$ go test -bench=.BenchmarkParity1000000&nbsp; &nbsp; &nbsp; &nbsp; 50&nbsp; &nbsp; &nbsp; 34586769 ns/op$
随时随地看视频慕课网APP

相关分类

Go
我要回答