RubyのCSVパースをPyCallで実行する(ベンチマーク)
目次

先日RubyからPythonにアクセスできるPyCallというライブラリの存在を知り、ぜひともベンチマークを取りたいと思った次第です。現状RubyのCSVの読み込みに不満を持っており、そこをどうにか解消したいと考えています。
PROBLEM
- 大量のCSVを読み込む際、毎回時間がかかる
SOLUTION
というわけで、「Dalibor Nasevicのベンチマーク記事」にPyCallのベンチマークをくわえて比較してみることにしました。記事では下記の通り CSV.foreach が速いとの結論でした。
| kind_of_parse | time (real) | memory (MB) |
|---|---|---|
1. CSV.read |
39.13 | 866.6 |
2. CSV.parse |
36.16 | 936.87 |
| 3. line by line from String Object | 23.39 | 73.42 |
| 4. line by line from IO Object | 24.55 | 0.0 |
5. CSV.foreach |
24.04 | 0.0 |
PyCallのベンチマーク
それでは、PyCallのベンチマークを計りましょう。コードは下記のようになります。
require_relative './helpers'
require 'pycall/import'
include PyCall::Import
pyimport :pandas, as: :pd
print_memory_usage do
print_time_spent do
csv = pd.read_csv.('data.csv')
sum = csv['id'].sum.()
puts "Sum: #{sum}"
end
end
PyCallは pyenv との相性が悪いのでSystemインストールしたPythonでたたきます。
$ PYTHON=/usr/bin/python3.4 ruby parse_6_pycall.rb
Sum: 499999500000
Time: 1.49
Memory: 54.99 MB
結果
| kind_of_parse | time (real) | memory (MB) |
|---|---|---|
1. CSV.read |
39.13 | 866.6 |
2. CSV.parse |
36.16 | 936.87 |
| 3. line by line from String Object | 23.39 | 73.42 |
| 4. line by line from IO Object | 24.55 | 0.0 |
5. CSV.foreach |
24.04 | 0.0 |
| 6. PyCall | 1.49 | 54.99 |
はい、結果が出ました。Daliborのベンチマーク記事で一番速かった CSV.foreach より16倍の実行速度となりました。
WRAPUP
PyCallのオブジェクトが PyObjectとActiveRecordと相性が悪そうなのと、PythonとRuby双方のメモリー管理が運用を難しくすることから、安易に本番環境のRailsに導入するのは厳しいと思います。
ただし、実行回数が限定されたスクリプトなら積極的に使って良いでしょう。
