ナレッジ

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

目次

thumbnail

先日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に導入するのは厳しいと思います。

ただし、実行回数が限定されたスクリプトなら積極的に使って良いでしょう。