国産プログラミング言語「Ruby」は、インタプリタ型のプログラミング言語であるため、「処理速度が遅そう」というイメージを持つ開発者の方もいるかもしれません。
しかし今回、Rubyで書かれたプログラムも工夫次第で十分高速に操作することを、John Hawthorn氏はブログ記事「Ruby might be faster than you think」で指摘し、Hacker NewsやRedditで注目を集めています。
同氏が例として掲載しているのは、crystalrubyと呼ばれる、Rubyの中からCrystalを呼び出すためのgemのサンプルプログラムです。
フィボナッチ数を計算するプログラムで、Pure Ruby版のfib_rb
とCrystalのコードを呼び出すfib_cr
の実行速度を比較しています。
require 'crystalruby'
require 'benchmark'
module Fibonnaci
crystalize [n: :int32] => :int32
def fib_cr(n)
a = 0
b = 1
n.times { a, b = b, a + b }
a
end
module_function
def fib_rb(n)
a = 0
b = 1
n.times { a, b = b, a + b }
a
end
end
puts(Benchmark.realtime { 1_000_000.times { Fibonnaci.fib_rb(30) } })
puts(Benchmark.realtime { 1_000_000.times { Fibonnaci.fib_cr(30) } })
最初は以下のように、Ruby版が大幅に遅い結果となりました。
$ ruby test.rb 2.113752398872748 0.6535678738728166
しかし同氏は、Rubyのブロックが配列を生成することに着目し、これを抑制することで速度を改善します(n.times{}の最後でnilを返しています)。
def fib_rb(n)
a = 0
b = 1
n.times { a, b = b, a + b; nil }
a
end
さらにブロックを普通のループに書き換え、最近のRubyで利用可能なYJITを使用することでPure Ruby版がCrystal版の速度を上回ることを示しています。
def fib_rb(n)
a = 0
b = 1
while n > 0
a, b = b, a + b
n -= 1
end
a
end
ruby --yjit
で実行します。
$ ruby --yjit test.rb 0.10502525512129068 0.5002881051041186
最終的にCrystal版より5倍高速度で、オリジナル版のRubyより20倍速い結果がでています。
同氏は、FFI(Foreign function interface)か、それに類するものによるコストが影響している可能性があるが、Rubyのコードに少し手を加えるだけで、大きく速度が向上するのは注目に値するとまとめています。
個人的には最終的な勝敗よりも、ブロックをループに展開することで速度が向上するところが興味深いと思いました。Rubyプログラムのパフォーマンスを改良したい場合に参考になるテクニックかもしれません。
タイトル | Ruby | |
---|---|---|
公式サイト | http://www.ruby-lang.org/ja/ | |
ソフトアンテナ | https://softantenna.com/softwares/1964-ruby | |
説明 | オブジェクト指向スクリプト言語。 |
タイトル | Crystal | |
---|---|---|
公式サイト | https://crystal-lang.org/ | |
ソフトアンテナ | https://softantenna.com/softwares/6966-crystal | |
説明 | Ruby風のシンタックス&静的な型を持つプログラミング言語 |