http://h-miyako.hatenablog.com/entry/2015/01/23/060000
自分が気になっている、主に最近のプログラミング言語でベンチマークをやってみました。方法は、42番めのフィボナッチ数列の値を計算する時間を測るだけです。フィボナッチで各種言語をベンチマーク - satosystemsの日記 を参考にさせていただきました。
- 注意
- 筆者はPythonくらいしか使ったことない素人です
言語紹介
測定した言語は、以下の11種類です。
選択基準は、
- メジャーっぽい
- 自分が知っていた
- 自分が気になった
- 環境構築が楽だった(or すでに構築済みだった)
- 怖くない
などです。気分と手間で選びました。
測定条件
2015年2月22日 10時16分 追記
Cの最適化オプションを
-O3
にするとNimよりCの方が速いとのことです。この記事では-O2
で実験していました。申し訳ありません。-O3
オプション付きでコンパイルすると、NimよりもCの方が若干速くなります。
Nim vs C 追実験した.10回実行して平均と分散を計算.C言語が早い(差は小さいが統計的に有意). Nim -d:release 平均4.2199秒 分散0.0018 C言語 -O3 平均 4.0689秒 分散0.0008
— ᴛ. ᴍᴀᴇʜᴀʀᴀ (@tmaehara) February 22, 2015
ソースコード
ベースのコードは単純なこれです(python)。
一応できる限り条件を揃えるため、以下のルールに沿って各言語のコードを用意しました。
- まず
n < 2
で条件分岐し、真ならそのまま n を返す - 偽ならば(elseは使わず)if節を抜け、関数の最後で
fib(n-1)+fib(n-2)
を返す - nはソースコードに直接書く
- 実行時に引数として与えたほうが公正な気はしますが、詳しくない言語で実行時にパラメータを受け取る方法を調べるのが面倒だったのでこの方式にします
- 最後に標準出力に結果を出力する
フィボナッチで各種言語をベンチマーク - satosystemsの日記 でベンチマークに使われている言語は、同じコードを一部変更して使わせていただきました。 問題がありましたらご連絡下さい。
C言語
とりあえず入れないとまずいですよね。
Dart
Google製の、いわゆるaltJSの一つ。 そのへんのaltJSと違うのは、JavaScriptの代替となることを狙っている点です。 Dartium上でそのまま実行することもできますし、JavaScriptに変換してから普通のブラウザ上で実行することもできます。
今回はDart VMで直接実行する場合と、JavaScriptに変換してからnode.jsで実行する場合の二通りを測定しました。 JavaScriptへの変換時間も、一応コンパイル時間として測りました。
Go 言語
引き続きGoogleの言語です。最近人気ですね。 私も結構好きですが、なんとなく流行に乗り遅れてしまった感じです。
JavaScript
これもやっといた方がいいだろう、という理由で入れました。 node.jsで実行してます。
Julia
手軽に書けて行末セミコロンもコンパイルも不要だけど速い、という言語。 メインターゲットは学術系っぽいと勝手に思ってます。 Matlab, Python (numpy, scipy, pandas, matplotlib), Rあたりが競合だと思います。
その速さは実際の所どうなのか、気になったのでエントリーです。
Lua/Luajit
ブラジル産まれ?のスクリプト言語。 軽量なので組み込まれて使われることが多いそうです。
一時Vim界隈で話題になっていたのでエントリー。 LuaJitも測りました。
Nim (旧称Nimrod)
この記事を書くきっかけのひとつは、Nimでフィボナッチ数列の計算をしてみたら妙に速かったことです。ぜひ他の方にもあの驚きを体験して欲しいです。 ちなみに、もうひとつのきっかけは後述するRustです。
Compileオプションの異なる以下二通りで計測しました。
- 最適化なし × 実行時チェックあり (
debug
)nim compile nim.nim
- 最適化あり × 実行時チェックなし (
release
)nim compile -d:release nim.nim
Python
Pythonです。個人的に好きといいますか、それなりの規模のコードを書いたことがあるのはPythonくらいです。 今回はPython2.7, PyPy, Python3.4, PyPy3 を試しました。
Ruby
日本産。最近はバージョンが上がるごとに速くなっているらしいので、1.9と2.0で測りました。
Rust
Mozilla謹製。 先日1.0.0-alpha がリリースされました。 おめでとうございます。
以前、このブログで記事を書いたこともありました。 その時の記事では、最適化無しの実行結果でGoと比較して遅いとか書いてしまいました。 最適化オプションに先日気づいて追記したのですが、アクセス数の雰囲気からけっこう多くの人が追記前に読んでいたようで、Rust関係の皆様には申し訳ない気持ちでいっぱいです。
ということで、Rustさんの汚名を雪ぐために、今回はちゃんと最適化して他の言語と比較します。むしろそれがこの記事を書く理由の半分です。
- 最適化なし
rustc rust.rs
- 最適化あり
rustc -O rust.rs
Vim Script
この記事はVimで書いています。
元々はVimの設定を記述するための言語だったはずですが、 日本語書籍(Vim script テクニックバイブル)が出版されるなど重要な言語になってきたので今回測定しました。
以下のコードで測定しました。
測定方法はもちろん他と同じようにtimeで実行から終了までです。 上記のコードを
vim.vim
として保存し、以下のように実行しました。
Vimの起動時間も含まれるの?という疑問もあるかもしれませんが、結果を見ればその疑問はなくなると思います。
測定環境
以下の環境で測定しました。
- OS: Ubuntu 14.04, linux 3.13.0-44-lowlatency (64bit)
- CPU: Core i7 の最初の頃の4コア8スレッド2.66GHz (i7 920?)
- Memory: 9GB
測定時はCPUのクロックを勝手に変えられないように一応 cpufreqd で100%固定にしました。
測定時は、測定スクリプトを
nice -n -15 ./benchmark.sh
と実行しました。 念の為、優先度を高めにしてます。
集計は手作業で行いました(一度きりしかやるつもりないので)。
測定結果
ソートなんてしません。アルファベット順です。
Language | Version | コンパイル時間 (s) | 実行時間 (s) |
---|---|---|---|
c | gcc 4.8.2 | 0.02 | 3.993 |
c (optimized) | gcc 4.8.2 | 0.29 | 2.062 |
dart | 1.8.3 | 0 | 5.139 |
dart2js with node.js | 1.8.3 / v0.11.11 | 1.607 | 5.583 |
go | 1.4.1 | 0.313 | 3.795 |
javascript | node v0.11.11 | 0 | 5.546 |
julia | 0.2.1 | 0 | 6.479 |
lua | 5.2.3 | 0 | 67.669 |
luajit | 2.0.2 | 0 | 4.962 |
nim | 0.10.2 | 0.795 | 25.996 |
nim (optimized) | 0.10.2 | 1.4 | 1.625 |
pypy | Python 2.7.3 (PyPy 2.2.1) | 0 | 20.617 |
pypy3 | Python 3.2.5 (PyPy 2.4.0) | 0 | 18.271 |
python2 | 2.7.6 | 0 | 120.652 |
python3 | 3.4.0 | 0 | 142.071 |
ruby1.9 | 1.9.3p484 | 0 | 72.74 |
ruby2.0 | 2.0.0p384 | 0 | 58.758 |
rust | 1.0.0-alpha | 0.29 | 4.692 |
rust (optimized) | 1.0.0-alpha | 0.303 | 3.602 |
vim script | 7.4.580 | 0 | 4449.79 |
せっかくなのでグラフにします。 ただ、そのまま描画すると Vim Script 以外見えなくなりそうなので、「1000秒間に何回計算が実行できるか」という数値に換算してグラフにします*2。 したがって、数値が「大きいほど速い」という事になります。 グラフの描画には Highcharts.js を使っています。
以下、適当にカテゴリ分けしてコメントします。
コンパイル言語組
実行時間だけの比較だと以下のような感じです。
[速い] C (
-O3
(仮)) > Nim (release) > C (-O2
) > Rust (optimized) > Go > C > Rust >>> Nim (degub) [遅い]
Nimのコンパイル時間がかなり長めに出ていますが、今回はキャッシュを使っていないことに留意してください。キャッシュがあると劇的に速くなります。このキャッシュは変更があっても有効です。例えば、今回のフィボナッチ数列のコードの最後に
echo(1)
という行を付け加えて再度コンパイルすると、約0.2秒で完了しました。したがって、実用上Nimのコンパイル時間が問題になるケースは少ないと言えます。JITコンパイル組
実行時間(秒)だけプロットします。
速度としてはLuaJitが最速で、Dart, JavaScript, Dart->JavaScript, Julia*3 までが同じくらい、大きく離れて PyPy 二種類という具合になりました。DartはさすがにJavaScript (Node.js)よりは速いですね。
PyPy以外はGoやRustに近い速度を出しています。今回のコードは単純だったので、ほとんどの計算がJITコンパイル後に行われたためでしょう。もっと複雑なコードではコンパイルする言語との差は大きくなりそうです。
PyPyが遅くてPython推しの自分としては悲しい限りです。PystonやNumbaもエントリーさせてなんとか一矢報いたかったのですが、あの二つはインストールのハードルが割と高かったため断念しました。CythonはもうCでいいじゃんって感じなので除外です。
[追記: 2015/04/20] コメント欄にてご指摘いただきました。 今回、Julia は Ubuntu の標準リポジトリのものを使ったので、古めのバージョン(v0.2.1, 2014/2/11 リリース)だったようです。 v0.3 で起動速度などが改善されているそうなので、気になる方は試してみてはいかがでしょうか。 [追加終わり]
残り(スクリプト言語組)
最後です。実行時間(秒)をプロットします。見やすくするため、桁がずれているVim scriptさんには枠外に飛び出てもらっています。
一番速いのはRuby 2.0です。Luaが一番速いと予想していたので意外でした。 Ruby 1.9でYARVに移行して大分速くなったそうですが、その後も高速化は続いているようです。2.1や2.2も試せれば良かったのですが、私はそんなにRubyが好きではないので諦めました。
Pythonは、Rubyとは逆に、2から3への移行で遅くなってしまっています。 推測ですが、これはPython3で整数型をPython2でのlong相当*4に一本化した影響ではないかと思います。 文字列操作ならもっと3系が速いのでは?と思われる方もいるかもしれませんが、Pythonの文字列型は2系では内部的にasciiだったのが3系ではUnicodeに統一され、メモリ消費が多くなっているので、やっぱり遅くなっているはずです。Pythonで速度が必要な処理を書く時はC APIを使いましょう。
Vim Scriptも有限時間内に完走出来てよかったと思いました(小並感)。
最後に
以上、なんとなくやってみたベンチマークでした。 結果を一言で表すと、
Nim速い!!RustもGoよりちょっと速い!!
でしょうか。なので皆さん、Nimを試しましょう。
単純な比較なので、各言語のごく一部しか比較できていませんが、ある程度特徴は出たのではないかと思っています。 また、一見公平に比較しているように見えて(特にコメントに)筆者の恣意的な何かが溢れています。鵜呑みにしないようご注意ください。 真面目に比較したい方はWebフレームワークのベンチマークなども参照するといいかもしれません。
0 件のコメント:
コメントを投稿