2011年1月30日日曜日

Javaはスクリプト言語より速い・・・のか?

このエントリーをはてなブックマークに追加
Clip to Evernote
Pocket

プログラミング言語人気TOP10の簡易解説』という記事が人気を呼んでいたのだが、軽快な語り口で面白い読み物だが、語弊がありそうな部分がある。その中で特に、「(Javaは)実行速度はCに及ばないもののスクリプト言語よりは数十倍速い」とある部分が気になったので、簡単な例で検証してみた。

1. Python、PHP、Java、Cで不適切な速度比較を行う

最初にコーディングが不適切な場合にプログラミング言語の速度比較を行うと、通説と異なる結果になる事を示したい。

Ubuntu Linuxで、オブジェクトをなるべく使わずに、順列の整数を100万個生成し、ランダムにシャッフルし、クイックソートを行ったときの経過時間を、timeコマンドで計測したものだ。ソート前、ソート後に配列の内容を、", "で連結して標準出力に書き出している。また、PythonはAPIをなるべく使ったもの(*無し)と、なるべく使わなかったもの(*有り)で計測した。CPythonを用いている。

100万レコードのクイック・ソート実行速度
Python
2.6.5
Python*
2.6.5
PHP
5.3.2
Java
1.6.0_22
gcc
4.4.3
real 2.469s 12.259s 3.956s 5.959s 0.531s
user 2.368s 12.165s 3.660s 3.532s 0.492s
sys 0.100s 0.080s 0.284s 2.424s 0.040s

ベンチマーク結果は、C、Python、PHP、Java、Python*の順番で速い。つまり、PythonやPHPが、Javaより速度が速くなっている。また、APIを使わないでスクリプトでクイック・ソートやシャッフルを実装した場合は、APIを使った場合より5倍弱遅い。適切なAPIを利用していくことが、スクリプト言語を使うコツになるのは確かなようだ。

2. Javaがスクリプト言語より遅くなった理由

オーバーヘッドの箇所は明確で、100万回もプリミティブ型を文字列オブジェクトに変換し、出力しているので、オブジェクト(インスタンス)の生成に時間がかかっている。これを文字列連結用のAPIを使い、インスタンス生成の回数を抑えると、下表のように劇的に速くなる。

Javaで高速化の工夫の有無による速度の差
工夫無し 工夫有り 削減幅
real 5.959s 0.854s -85.7%
user 3.532s 0.672s -81.0%
sys 2.424s 0.180s -92.6%

100万回のSystem.out.println()の呼び出しを、StringBuilderを使い1回にしただけだが、85%以上の時間を削減する事ができている。逆に言うと、Javaは油断すると遅いコードになりやすい

3. C、Java、Python、Perl、PHP、Rubyで300万件のソートにかかる時間を比較する

せっかくなので、人気のスクリプト言語Python、Perl 5.10.1、PHP、Ruby 1.8.7の速度差を評価してみる。ベンチマークとして、C、C++とJavaを併記している。CとJavaは書き方によって速度が大きく変化するが、Javaは上述の工夫と、Cはitoa関数の高速化版を用いた。C++はテンプレート・クラスvectorとrandom_shuffleを用いてC++らしくし、あえてCとの差をつけている。

300万レコードのソートにかかる時間
real user sys C言語比
C 1.478 1.432 0.040 1.0
C++ 1.806 1.736 0.068 1.2
Java 2.629 2.168 0.408 1.5
Python 7.999 7.832 0.160 5.5
Perl 10.339 9.673 0.648 6.8
PHP 13.777 12.849 0.868 9.0
Ruby 24.193 22.357 1.788 15.6
JRuby 15.543 13.677 1.936 9.6

結果はCとC++が傑出しており、次にJava、だいぶ離されてPython、Perl、PHP、最後尾にRubyがつく形となっている。RubyはJRuby 1.6.0RC1よりも遅く、最新版の1.9.2 p136でも大きな速度の改善は見られなかった。なお今回のベンチマークで利用したプロセッサはAMD Phenom IIで、Intel系のプロセッサを用いた場合、異なる結果が出る可能性がある。

追記(2011/2/3):Cのソースコードに問題が発見されたので、結果に訂正を入れた。また、CとC++の速度差だが、純粋なソート時間ではCが0.518秒、C++が0.237秒程度となっており、テンプレート・ライブラリの高速性が否定されたわけでは無い。

4. プログラム言語の速い・遅いは難しい

上述のベンチマークからは、C > Java > スクリプト言語の処理速度となり、Javaとスクリプト言語の速度差も4~10倍程度で、概ね通説と一致する結果となった。しかし、ちょっとした前提条件でJavaとスクリプト言語の処理速度の差が逆転することも事実だ。また、複雑な演算があるコードならJavaの方が速くなると考えられるが、文字列処理とデータベースとのやり取りが主な場合は、何十倍の速度差はつかないと思われる。

近年はソフトウェアの速度に対する要求は年々低くなってきているので、稼働環境や職場の事情などが許すならば、プログラマが快適に書ける言語を選択するべきであろう。嫌いな言語で不適切なコードを書くよりも、好きな言語で適切なコードを書く方が、結局は速度的にも有利なことが多いからだ。お気に入りのプログラミング言語を使いこなす事を心がけた方が、実行速度が出る慣れない言語に頼るよりも、より良いソフトウェアを作れる事が多いように感じる。

0 コメント:

コメントを投稿