【Rust】【TypeScript(JavaScript)】実行速度の比較

tl;dr

Rust は TypeScript(JavaScript) より早い

バージョン

Rust

cargo 1.28.0 (96a2c7d16 2018-07-13)

TypeScript(JavaScript)

node v11.2.0
tsc Version3.1.3

内容

事の発端

「Rustは安全性、速度、並行性の3つのゴールにフォーカスしたシステムプログラミング言語です。」と書かれているのをドキュメントで見かけ、ではどの程度早いのか知りたくなったのが事の発端です。

ルール

数独の回答を検証するスクリプトを実行し、完了速度を比較します。この時、以下の条件に従ったコードを書きます。

      入力は数独の正解データ1つを用いる。この時、データの形式は左上が1文字目として右に向かって順に数えていき、右下を81文字目とした半角数字81桁の文字列とする。
      タテ列、ヨコ列、3×3のブロックを9つずつ、それぞれ27個に1から9の数字が入っていることの検証を1回とし、100000回実行した際の完了時間を比較する。

Rust のコード

use std::time::Instant;

fn main() {
    // 初期条件
    let target: Vec = "864371259325849761971265843436192587198657432257483916689734125713528694542916378".chars().collect();

    let start = Instant::now();

    for _bench in 0..100000 {
        for x in 0..9 {
            // 横
            let segment_record = x * 9;
            is_fill_condition_9(target[segment_record + 0],target[segment_record + 1],target[segment_record + 2],target[segment_record + 3],target[segment_record + 4],target[segment_record + 5],target[segment_record + 6],target[segment_record + 7], target[segment_record + 8]);

            // 縦
            is_fill_condition_9(target[x + 0],target[x + 9],target[x + 18],target[x + 27],target[x + 36],target[x + 45],target[x + 54],target[x + 63], target[x + 72]);

            // ボックス
            let segment_box = 3 * (x % 3) + 27 * (x / 3);
            is_fill_condition_9(target[segment_box + 0],target[segment_box + 1],target[segment_box + 2],target[segment_box + 9],target[segment_box + 10],target[segment_box + 11],target[segment_box + 18],target[segment_box + 19], target[segment_box + 20]);
        }
    }

    let end = start.elapsed();
    println!("{}{:03}s", end.as_secs(), end.subsec_nanos() / 1000000);
}

///
/// 指定された9つの要素が数独の条件を満たしていること
///
fn is_fill_condition_9(n1: char, n2: char, n3: char, n4: char, n5: char, n6: char, n7: char, n8: char, n9: char) -> bool {
    let mut target = vec![n1, n2, n3, n4, n5, n6, n7, n8, n9];

    target.sort();
    return target == ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
}

TypeScript(JavaScript) のコード

const main = (): void => {
    // 初期条件
    const target: Array = "864371259325849761971265843436192587198657432257483916689734125713528694542916378".split("");

    const start: Date = new Date();

    // ベンチマーク
    for (let bench: number = 0; bench < 100000; bench ++){
        for (let x: number = 0; x < 9; x++) {
            // 横
            const segmentRecord = x * 9;
            isFillCondition9(target[segmentRecord + 0],target[segmentRecord + 1],target[segmentRecord + 2],target[segmentRecord + 3],target[segmentRecord + 4],target[segmentRecord + 5],target[segmentRecord + 6],target[segmentRecord + 7], target[segmentRecord + 8]);

            // 縦
            isFillCondition9(target[x + 0],target[x + 9],target[x + 18],target[x + 27],target[x + 36],target[x + 45],target[x + 54],target[x + 63], target[x + 72]);

            // ブロック
            let segmentBox = 3 * (x % 3) + 27 * Math.floor(x / 3);
            isFillCondition9(target[segmentBox + 0],target[segmentBox + 1],target[segmentBox + 2],target[segmentBox + 9],target[segmentBox + 10],target[segmentBox + 11],target[segmentBox + 18],target[segmentBox + 19], target[segmentBox + 20]);
        }
    }

    const end: Date = new Date();
    console.log(`${end.getTime() - start.getTime()}ms`);
};

/**
 * 指定された9つの要素が数独の条件を満たしていること
 * 
 * @param n1
 * @param n2
 * @param n3
 * @param n4
 * @param n5
 * @param n6
 * @param n7
 * @param n8
 * @param n9
 */
const isFillCondition9 = (n1: string, n2: string, n3: string, n4: string, n5: string, n6: string, n7: string, n8: string, n9: string): boolean => {
    const target = [n1, n2, n3, n4, n5, n6, n7, n8, n9];
    
    target.sort();
    return target.toString() === ["1", "2", "3", "4", "5", "6", "7", "8", "9"].toString();
};

main();

結果

結果を確認したところ、 Rust より TypeScript(JavaScript) の方が早い結果を得られました。

$ cargo build
   Compiling rust_hello_world v0.1.0
    Finished dev [unoptimized + debuginfo] target(s) in 0.80s
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/rust_hello_world`
7896ms

$ tsc main.ts
$ node main.js
3856ms

流石にそんなことは無いだろうと思って確認したところ、コンパイルと実行はデフォルトではデバッグモードで行われるため、そのままだと最適化されていないことが原因だそうです。
で、高速化するためには

--release

を使えば良いとのことでした。

$ cargo build --release
   Compiling rust_hello_world v0.1.0
    Finished release [optimized] target(s) in 0.57s
$ cargo run --release
    Finished release [optimized] target(s) in 0.04s
     Running `target/release/rust_hello_world`
0129ms

7896ms -> 129ms なので60倍くらい違いますね。
TypeScript(JavaScript) と比較しても 3856ms と 129ms なので30倍くらい違う。
これは早い。

参考