2010年7月24日土曜日

Rubyで遅延評価

いろんなところで既にやられているけど、自分でやってみたくなったので。
遅延評価とは、計算結果が実際に必要になるまで処理を遅延すること。

a = huge_proc()
b = large_proc()
print a

この仮想コードのhuge_procの呼び出しは、3行目のprintで出力されるまで遅延される。また、bは使われていないのでlarge_procは呼び出されない。
こういった仕組みがあれば、処理に時間がかかるが戻り値を使うかどうか分からない関数をムダに実行することがなくなるので、ある種の処理は非常に早くなる。これをRubyでやりたい。

実装

今回作ったユーティリティは、lazy{ 遅延させたい処理 }のように使い、戻り値として遅延オブジェクトを返す。
使い方は例えば、a = lazy{ x }と書けば、lazy自体はすぐに遅延オブジェクトを返し、aのメソッドが呼ばれたときに初めてxが実行される。

class Lazy
  def initialize
    @proc = Proc.new
    @obj = nil end

  def method_missing(method, *args, &block)
    if @proc
      @obj = @proc.call
      @proc = nil end
    @obj.__send__(method, *args, &block) end end

def lazy(&proc)
  Lazy.new(&proc) end

method_missingは、メソッドが無かった時に呼び出されるメソッドで、このメソッドはブロックの戻り値のオブジェクトのメソッドを呼び出す。これによって、遅延オブジェクトから実行結果のオブジェクトのメソッドを透過的に呼べる。

竹内関数によるベンチマーク

試しに、竹内関数(たらい回し関数)の遅延版と通常版と最適化版を作って、どちらも同じ引数(12,6,0)を指定して、速度の差を計測してみた。

def tak(x, y, z)
  if x <= y.to_i
    y
  else
    tak(tak(x-1, y, z), tak(y-1,z,x), tak(z-1,x,y)) end end

def ltak(x, y, z)
  lazy{
    if x <= y.to_i
      y
    else
      ltak(ltak(x-1, y, z), ltak(y-1,z,x), ltak(z-1,x,y)) end } end

def btak(x, y, z)
  if x <= y.to_i
    y
  else
    btak(btak(x-1, y, z), btak(y-1,z,x), lazy{ btak(z-1,x,y) }) end end

a = Benchmark.realtime{ tak(12,6,0).to_i } # => 9.08182191848755
b = Benchmark.realtime{ ltak(12,6,0).to_i } # => 0.00162792205810547
c = Benchmark.realtime{ btak(12,6,0).to_i } # => 0.000227928161621094
a / b # => 5578.78178090217
a / c # => 39845.1066945607
b / c # => 7.14225941422594

関数ltakは、takの内容をlazyで囲っただけで、takは素直な竹内関数の実装。btakは、takの第一引数と第二引数は必ず必要になる=遅延する必要がないので第三引数だけを遅延したバージョンだ。

通常9秒かかるこの計算が、ltakだと10ミリ秒に、btakでは2ミリ秒になり、btakはtakに比べて39845倍の速度になった。

まとめ
当然だが、遅延オブジェクトの生成にもオーバヘッドがあるので、必要以上に使うことは却って速度の低下につながるので避けたい。
また、この類のコードは汎用性が高いので、もうすこし実装を詰めてもいいかもしれない。
例えば、is_a?等、Objectクラスのメソッドが適切に動くようにすれば、関数の内部の処理を考えずに遅延オブジェクトを渡したり返したり出来るだろう。

12 件のコメント:

  1. Great . Keep writing such beautiful blogs. Turkey visit visa requirements are updated as per the requirement of Time . And you can also read all the important information about the Turkey entry requirement by 1 click.

    返信削除

  2. I really love reading such a good article.Helpful article. You can come to India but you will need a visa. You can apply online visa for India. You can read all the info about Indian visas via our website.

    返信削除
  3. Hello guys, many people ask, how can I apply for a visa? You can e visa apply online. And your visa processing time depends on your nationality and your visa type.

    返信削除
  4. bonus veren sitelerhttps://casinosallinfo.com2023年1月4日 16:02

    Good text Write good content success. Thank you
    mobil ödeme bahis
    slot siteleri
    poker siteleri
    betpark
    kibris bahis siteleri
    kralbet
    betmatik
    tipobet

    返信削除
  5. Your blog post embarks on a captivating exploration of complex concepts, skillfully marrying clarity with depth. The seamless fusion of well-researched facts and personal insights creates a narrative that resonates profoundly. Your unique voice and perspective enrich the discourse making this read both informative and thought provoking

    返信削除
  6. Blog writing is part of my daily life, and I'm struck by the excellence of your articles. Your recent piece was especially captivating. I've saved your site to my bookmarks and plan to follow along with new posts on a weekly basis through your RSS feed.
    "how much does e visa to india cost? "The cost of an e-visa to India varies depending on the applicant's nationality and the type of visa required. For the most accurate pricing, please check the official visa application website."

    返信削除