ちょっと業務で大量のテキスト処理をしないといけない案件がありましてRubyで作ってたんですが、それがどうにも遅い…。コード的にチューニングする余地はあるのですが、そもそも遅いヤツを使っているんじゃ話にならんなということで、主要なLLでの速度の差を測ってみることにしました。
まずは測定結果
ちょっとしたテキスト(6MB)の場合はPerl圧勝、大きなテキストの場合はPython勝利となりました。Rubyはいずれの場合も僅差で最下位を免れていますが遅めですね。PerlとPythonが得意・不得意が大きく分かれたのとは対照的です。
ちなみに測定条件
- Nginxのアクセスログから正規表現でIPアドレスを抽出
- 抽出結果をファイルに書く
- 使用マシンはFDなCore i5のiMacさんです
- 全て3回ずつ計測
- 異常値(極端に外れた値)は出ていなかった
今更ながらの出場選手紹介
まずはRuby選手から
show_ruby_version
$ ruby -v
ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-darwin12.3.0]
使用するコードは次の通り
regex_test.rb
#!/usr/bin/env ruby
re_addr = /((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))/
fh2 = open("./result_rb.txt", "w")
open("./access.log.1") { |fh|
while line = fh.gets
if m = re_addr.match(line)
fh2.puts m[1]
end
end
}
fh2.close
次にPython選手
show_python_version
$ python --version
Python 2.7.2
使用するコードは次の通り
regex_test.py
#!/usr/bin/env python
import re
re_addr = re.compile("((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))")
fh2 = open('./result_py.txt', 'w')
fh = open('./access.log.1')
for line in fh.readlines():
m = re_addr.search(line)
if m is not None:
fh2.write(m.group(1))
fh2.write("\n")
fh.close()
fh2.close()
最後に大ベテランのPerl選手
show_perl_version
$ perl -v
This is perl 5, version 12, subversion 4 (v5.12.4) built for darwin-thread-multi-2level
#(長いので以下省略)
使用するコードは次の通り
regex_test.pl
#!/usr/bin/env perl
open(FH2, ">", "./result_pl.txt");
open(FH, "<", "./access.log.1");
while($line = readline FH) {
if ($line =~ /((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))/) {
print FH2 $1."\n";
}
}
close(FH);
close(FH2);
こんな感じで、各言語共にロジックはほぼほぼ一緒で、また、たいしたことはしていません。
あとがき
正規表現+ファイル書き込みなので、純粋な正規表現能力の比較ではありません。とはいえ、このベンチマークをするきっかけが大量テキストの処理(正規表現で特定のデータを抜き出し、ファイルに書き出す)なので、そこはご容赦ください…。
各言語のメモリ解放などをちゃんと考慮できていないので、そういったあたりをちゃんとするとまた結果は変わるかもしれません。あくまで参考程度にどうぞ。