为什么在执行相同的按位和I / O操作时,我的Rust程序比Go程序慢4倍? [重复]

This question already has an answer here:

I have a Rust program that implements a brute-force parity check for 64-bit unsigned integers:

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));
    }
}

When I feed it with input file containing 1000000 unsigned integers:

$ 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

And here comes a surprise - the effectively same program in Go does 4x faster:

$ 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

Here's the code in 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)
    }
}

Versions:

$ rustc --version
rustc 1.7.0
$ go version
go version go1.6 darwin/amd64

Sample of input file, first line contains number of input values in the file:

8
7727369244898783789
2444477357490019411
4038350233697550492
8106226119927945594
1538904728446207070
0
1
18446744073709551615

Why do the Rust and Go programs I've written have such a dramatic difference in performance? I expected Rust to be a bit faster than Go in this case. Am I doing something wrong in my Rust code?

</div>

I think you're not compiling with optimisation. try

$ rustc -O parity.rs

Your benchmark doesn't measure the parity check. It measures input plus parity check plus output. For example, in Go, you measure scanner.Scan and strconv.ParseUint and fmt.Println as well as the parity check.

Here's a Go benchmark that just measures 1000000 parity checks.

parity_test.go:

package parity

import (
    "math/rand"
    "runtime"
    "testing"
)

func parity(n uint64) uint64 {
    var parity uint64
    for n > 0 {
        parity ^= n & 1
        n >>= 1
    }
    return parity
}

func init() { runtime.GOMAXPROCS(1) }

// Benchmark 1000000 parity checks.
func BenchmarkParity1000000(b *testing.B) {
    n := make([]uint64, 1000000)
    for i := range n {
        r := uint64(rand.Uint32())
        n[i] = (r << 32) | r
    }
    p := parity(42)
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        for _, n := range n {
            p = parity(n)
        }
    }
    b.StopTimer()
    _ = p
}

Output:

$ go test -bench=.
BenchmarkParity1000000        50      34586769 ns/op
$