Elixirでフィボナッチ数を計算してみる
このごろ流行のruby風味の関数型言語「Elixir」でフィボナッチ数を計算してみました。
そして、これまた、このごろ流行の関数型言語Rustで実装したフィボナッチ数を求めるプログラムを呼び出して、速度比較をしてみました。
とくに意味はありません。
環境
マシン
- Microsoft Windows 10 Home
- Intel64 Family 6 Model 78 Stepping 3 GenuineIntel ~2300 Mhz
- 3,935 MB
Elixr
- Erlang/OTP 18 [erts-7.2.1] [64-bit] [smp:4:4] [async-threads:10]
- Elixir 1.3.1
Rust
- rustc 1.9.0 (e4e8b6668 2016-05-18)
- cargo 0.10.0-nightly (10ddd7d 2016-04-08)
検証したソースコード
どちらの言語もまだまだ初学者レベルなので、細かいところがおかしい場合はご指摘願います。 また、「こうした方が早くなる」等のアドバイスも非常に助かりますので、お時間があればご教示願います。
fibonacci.ex
defmodule Fibonacci do def start do [num_string|_] = System.argv num = String.to_integer(num_string) exec_cmd = "lib/rust_fib.exe " <> num_string IO.puts "Elixir fibonacci" {result_elixir, :ok} = :timer.tc(Fibonacci, :fibonacci_elixir, [num]) IO.puts "#{result_elixir/1000}ms" IO.puts "Rust fibonacci" {result_rust, :ok} = :timer.tc(Fibonacci, :fibonacci_rust, [exec_cmd]) IO.puts "#{result_rust/1000}ms" end # Elixirのみで計算する場合 def fibonacci_elixir(num) do IO.puts fibonacci(num) end def fibonacci 0 do 0 end def fibonacci 1 do 1 end def fibonacci(num) when (is_integer num) and (num > 0) do fibonacci(num - 1) + fibonacci(num - 2) end # Rustプログラムを呼び出す場合 def fibonacci_rust(exec_cmd) do port = Port.open({:spawn, exec_cmd}, [:binary]) Port.command(port, "") receive do {^port, {:data, result}} -> IO.puts(String.trim(result)) end end end Fibonacci.start
rust_fib.rs
use std::env; fn calc_fibonacci(n: u32) -> u32 { if n <= 1 { n } else { calc_fibonacci(n - 1) + calc_fibonacci(n - 2) } } fn fibonacci(mut argv: env::Args) -> Result<u32, String> { let arg1 = try!(argv.nth(1).ok_or("数字を1つ指定してください。".to_owned())); let n = try!(arg1.parse::<u32>().map_err(|err| err.to_string())); Ok(calc_fibonacci(n)) } fn main() { match fibonacci(env::args()) { Ok(n) => println!("{}", n), Err(err) => println!("{}", err), } }
結果
※ ms単位にしたため、us単位の数値が消えて0msになっています。すみません。
※ 与える数値が低い範囲(0~25くらいまで)は速度の数値が安定しなかったので、何度か計測して頻度の高い数値を使っています。
※ 画像出力の際に表の縦線が消えました。
- 0から26までは、Elixirの計算速度の方が早いようです。と言っても、Elixir+Rustが遅いのではなく、外部プログラムを呼び出して結果を受けるまでのオーバーヘッドが必ず入ってしまうので遅くなる感じですね。
- 27で双方が肩を並べ、30から外部プログラムの恩恵を受けられるようになりました。
- 45では、Elixir+Rustの方が10倍早い結果が出ています。
まとめ
- Elixirは書きやすい。Rustは少し取っつきにくかったです。
- Elixirが遅いときは、重い処理を簡潔な外部プログラムで実装してPortで呼び出すという手もある。
- 外部プログラムの呼び出しに一定のコストがかかるので、Elixirの実行速度が比較的遅いからと言って、むやみやたらに外部プログラムを呼ぶものではないと感じました。