Edited at

「様々な言語でMap, Filter, Reduceを実現してみた」をRust&Rubyでやってみた


これは何?

様々な言語でMap, Filter, Reduceを実現してみた(1)の記事を見てRustRubyでやってみたというだけの記事です。


環境


  • MacBook Pro (2018)

  • macOS Mojave 10.14.4

  • rustc 1.34.1

  • ruby 2.6.2p47


コード

※制限事項「生成したデータはイテレータオブジェクトではなく、実体データの集合になるようにした」に則ってコードを修正済み


Rust

fn main() {

let a = (0..10_000_000).collect::<Vec<i64>>();
let res = a
.iter()
.map(|a| a * 2)
.filter(|&a| a % 3 == 0)
.fold(0, |acc, x| acc + x);
println!("{}", res);
}


Ruby

class Integer

def twice
self * 2
end

def div3?
self % 3 == 0
end
end

a = (0..10_000_000 - 1).to_a
puts a.map(&:twice).select(&:div3?).sum


計測

mfr.rsおよびmfr.rbというファイル名にしました。


Rustの場合

$ cargo b --bin mfr --release

$ time ./target/release/mfr
33333336666666

real 0m0.016s
user 0m0.012s
sys 0m0.003s

環境差異があるとはいえ、元記事C++のケースより速いのはなぜでしょう…?

(追記)ルール違反してた。



  • 生成したデータはイテレータオブジェクトではなく、実体データの集合になるようにした


というわけで、Rangeオブジェクトのままmap/filter/foldするのではなく、一旦Vec<i64>collectしてから実行するように修正。Rubyも同様。

$ time for i in `seq 1 1000`; do ./target/release/mfr ; done

(中略)
33333336666666

real 1m4.037s
user 0m29.641s
sys 0m31.654s

1回あたりの処理にかかる時間はおよそ12msec。標準出力に吐く処理で3msecぐらい(文字列を出力するプログラムで測った)なので、コンパイル時に計算しているわけではなさそうです。

だいたい1処理あたり64msですね。それでも微妙に元記事のC++のケースより少し速い。


Rubyの場合

上記環境での1回の実行で1.9秒ぐらいかかった。

$ time ruby mfr.rb 

33333336666666

real 0m1.946s
user 0m1.777s
sys 0m0.129s