iT邦幫忙

0

怎麼讓 Rust 跑得快一點

寫個小程式,用暴力的方法不斷地找出 10000000 之後的質數,本來想說 Rust 和 Go 幾乎相同的寫法應該會差不多的,不過實際執行時 Go 卻明顯快很多,實在搞不懂怎麼回事,特來請教,謝謝。

// Rust

fn main() {
    println!("Hello, Rust");

    let mut i: u64 = 10000000;
    let mut c: u64 = 0;

    loop {
        c = 0;

        for j in 2..i {
            if i % j == 0 {
                c += 1;
            }
        }

        if c == 0 {
            println!(
                "i = {}, c = {}\t>>=======> {} is a prime. By Rust!",
                i, c, i
            );
        } else {
            println!("i = {}, c = {}", i, c);
        }

        i += 1;
    }
}
// Go

package main

import "fmt"

func main() {
        fmt.Printf("Hello, Go")

        var i uint64 = 10000000
        var c uint64 = 0

        for {
                c = 0
                for j := uint64(2); j < i; j++ {
                        if i%j == 0 {
                                c = c + 1
                        }
                }

                if c == 0 {
                        fmt.Printf("i = %d, c = %d\t>>=======> %d is a prime. By Go!\n", i, c, i)
                } else {
                        fmt.Printf("i = %d, c = %d\n", i, c)
                }

                i = i + 1
        }
}

$ rustc -vV
rustc 1.38.0
binary: rustc
commit-hash: unknown
commit-date: unknown
host: x86_64-unknown-linux-gnu
release: 1.38.0
LLVM version: 7.0
rust 編譯時要用 cargo build --release
https://doc.rust-lang.org/cargo/commands/cargo-build.html
才會最佳化, 這樣才會快. 一般是會增加除錯,也沒最佳化.
sendxph iT邦新手 5 級 ‧ 2019-10-24 11:58:17 檢舉
謝謝大大, 讓我知道問題是出在沒有做最佳化, 謝謝您的寶貴意見
0
DanSnow
iT邦新手 2 級 ‧ 2019-10-24 10:22:52
最佳解答

因為你這樣是無窮迴圈,如果要計時來比較速度的話沒辦法比,所以我這邊先改了一下你的程式,讓它們跑到同一個數字就停下來:

Rust:

fn main() {
    println!("Hello, Rust");

    for i in 10000000..10000500 {
        let mut c: u64 = 0;
        for j in 2..i {
            if i % j == 0 {
                c += 1;
            }
        }

        if c == 0 {
            println!(
                "i = {}, c = {}\t>>=======> {} is a prime. By Rust!",
                i, c, i
            );
        } else {
            println!("i = {}, c = {}", i, c);
        }
    }
}

Rust 用 rustc -O -o prime-rs prime.rs 編譯

Go:

package main

import "fmt"

func main() {
	fmt.Printf("Hello, Go")

	var c uint64

	for i := uint64(10000000); i < 10000500; i++ {
		for j := uint64(2); j < i; j++ {
			if i%j == 0 {
				c = c + 1
			}
		}

		if c == 0 {
			fmt.Printf("i = %d, c = %d\t>>=======> %d is a prime. By Go!\n", i, c, i)
		} else {
			fmt.Printf("i = %d, c = %d\n", i, c)
		}

		i = i + 1
	}
}

Go 則是用 go build -o prime-go prime.go 編譯,預設 Go 似乎就會最佳化了,所以這邊就沒另外加什麼參數
https://stackoverflow.com/questions/45003259/passing-an-optimization-flag-to-a-go-compiler

然後都用 hyperfine 測速度得到以下結果:

Command Mean [s] Min [s] Max [s] Relative
./prime-rs 13.185 ± 0.026 13.151 13.245 1.0
./prime-go 20.795 ± 0.094 20.701 21.018 1.0

其實這樣光這樣就可以看到 Rust 已經比較快跑完了,但如果把 Rust 的程式再修改一下,中間的 for j in 2..i 這段改成以下這樣,用 Iterator 做的話:

 let c = (2..i).filter(|j| i % j == 0).count();

再跑一次結果:

Command Mean [s] Min [s] Max [s] Relative
./prime-rs 11.558 ± 0.077 11.488 11.713 1.0

所以並沒有 Rust 跑比較慢這回事,有可能是你沒有開最佳化之類的原因導致的

另外補充一下我測試的環境

$ rustc -vV
rustc 1.40.0-nightly (e413dc36a 2019-10-14)
binary: rustc
commit-hash: e413dc36a83a5aad3ab6270373000693a917e92b
commit-date: 2019-10-14
host: x86_64-unknown-linux-gnu
release: 1.40.0-nightly
LLVM version: 9.0
$ cat /proc/cpuinfo
...
model name      : Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz
...
sendxph iT邦新手 5 級 ‧ 2019-10-24 12:08:06 檢舉

DanSnow 大大

請原諒我的無知, 也謝謝您點出我的問題, 原來 rustc 有加參數 O 和沒加參數 O 差別這麼大, 完全不是同一個級別.

在沒有修改程式碼的情況下, 用不同參數編譯後, 開不同 terminal 和 GO 做比較, 有加參數 O 的程式已經比 GO 要快了. 我也把標題修改了一下, 免得造成了誤解, 謝謝您!

0
阿展展展
iT邦好手 1 級 ‧ 2019-10-24 05:44:41

效能分析
Go 的簡便無所不在,連讓程式最佳化的工具也不例外。從效能分析(profiling)來看,Go 內建追蹤 CPU 和記憶體用量的機制,且能與 pprof 工具整合。可以很容易檢查 Go 程式並取得有用的資料來最佳化。

我還沒發現任何 Rust 的分析工具可以和 Go 的工具一樣整合 pprof。當然,有一個函式庫可以生成類似 pprof 的追蹤資料,但我無法簡易上手,安裝上也有點詭異(需要 gperftools 以顯示在系統上)。這篇舊文有相關資訊和工具可供參考。

獲勝者:就我目前所知,Go 在這方面大勝。

Rust vs. Go

sendxph iT邦新手 5 級 ‧ 2019-10-24 15:59:25 檢舉

謝謝您, 阿展展展大大.

0
海綿寶寶
iT邦大神 1 級 ‧ 2019-10-24 09:49:43

跑程式的快慢與許多環境因素有關
硬體、作業系統、程式寫法、題目類型...

根據 Russ Cox 的說法
只有 fannkuch-redux, fasta, k-nucleotide, mandlebrot, nbody, reverse-complement and spectral-norm 這幾類的題目
比較可以拿來公平地比較 Go 與其他語言

有時間可以看看別人的測試結果

sendxph iT邦新手 5 級 ‧ 2019-10-24 16:00:47 檢舉

編譯時沒有最佳化造成的問題, 謝謝大大的提醒/images/emoticon/emoticon41.gif

我要發表回答

立即登入回答