2年くらい前の記事だが、こんな記事が気になったので補足する。
俺の言語がこんなに遅いわけがない!? 〜C, Java, PHP, Python, Rubyによるプログラミング言語 速度比較〜
確かにスクリプト言語は遅い。ただし、C言語で一般的なアルゴリズムをそのまま使って計算したとしたら。
スクリプト言語にはスクリプト言語なりの流儀があり、慣れている人は違う方法で実装する。
ちょうどPythonについて、同じようなことを先日ソフトウェアジャパンというイベントでしゃべって来たのでこのスライドも参照されたい。
ここで改めてベンチマークをとってみたい。まずはPythonから。Pythonではこの手の数値計算をするのはNumpyというライブラリを使うのが普通である。Numpyで1からnが入った配列を用意し、そのメソッドsum()で合計を計算する。
結果の格納先になぜ辞書型を使うのかなど、気に入らないところもあるが、和の計算以外は上記リンク先のベンチマークコードをそのまま使う。
N = 10000 import numpy as np def sumup(n): return np.arange(1, n + 1).sum() def main(): print("python with numpy start.") result = {} for count in range(1, N + 1): result[count - 1] = sumup(count) print("python with numpy end.") main()
Pythonの数値計算でNumpyを使うのは充分に一般的だと思うが、Python本体に含まれてないライブラリを使って「Pythonのベンチマーク」と主張することに違和感を感じる人がいるかもしれないので、Numpyを使わない版も実験してみる。その場合、1からnが入ったリストを用意してsumという関数を適用するのが普通かと思う。
N = 10000 def sumup(n): return sum(range(1, n + 1)) def main(): print("python without numpy start.") result = {} for count in range(1, N + 1): result[count - 1] = sumup(count) print("python without numpy end.") main()
次にRubyで実験してみる。Rubyの配列にはinjectというメソッドがあるのでそれを利用してみる。
N = 10000 def sumup(n) return (1..n).inject{ |sum, x| sum + x } end def main() result = [] puts "ruby start." (1..N).each do |count| result[count-1] = sumup(count) end puts "ruby end." end main()
C言語は、参照先ブログのコードをそのまま使い、最適化なし(オプション-O0)と最適化あり(-O3)を試してみる。
#include <stdio.h> #define N 10000 long sumup(int n) { int i; long sum = 0; for (i=1; i<=n; i++) { sum += i; } return sum; } int main() { int count; long result[N]; printf("c start.\n"); for (count = 1; count <= N; count++) { result[count-1] = sumup(count); } printf("c end.\n"); return 0; }
参照先ブログにあるJavaとPHPはここでは無視する。
ベンチマーク結果
AWSのt2.microで、それぞれのバージョンは以下のとおり
OS: Ubuntu 14.04.3 LTS
Python: 3.5.1
Ruby: 1.9.3p484
gcc: 4.8.4
参照先にあるようにtimeコマンドで測定した。
言語 | 計算時間(msec) |
---|---|
Python(Numpyあり) | 167 |
Python(Numpyなし) | 739 |
Ruby | 4159 |
C言語(最適化なし) | 185 |
C言語(最適化あり) | 1 |
考察
最適化付きのC言語が速すぎるのは、最適化しすぎて何もやっていないからである。アセンブリコードを吐かせて確認したが、main関数からsumup関数の呼び出し自体が消えている。なので、これと他を比べるのはあまり意味がないかと思う。
Python+Numpyは爆速であることがわかる。Numpyなしでもそれなりの速さは出ている。この結果だけをみるとRubyが遅いようだが、にしても参照先ブログからかなり速くなっており、受ける印象が随分違うと思う。
まとめ
- C言語と同じような発想で同じアルゴリズムをそのまま実装するとスクリプト言語は非常に遅い
- しかしスクリプト言語はスクリプト言語なりの流儀があり、慣れている人はどうすれば速くなるか知っている。そのコードはC言語とかけ離れることもある。
更新履歴:
2016/2/11 誤植の修正と若干の加筆
ピンバック: MF / Ruby/NArray遅くないよ
Rubyを擁護してみました
rubyに対して不平ですよ。
def sumup(n)
(1..n).sum
end
sumupのところにこうしたら爆速です。python with numpyより早いですよ。
情報ありがとうございます。調べてみましたが、そのsumメソッドはRuby 2.4.0で導入されたようです。
https://docs.ruby-lang.org/en/2.4.0/NEWS.html
Ruby 2.4.0のリリースが2016年の12月25日ということですので、このブログよりあとで追加された機能のようです。