無駄なProcオブジェクトは作らないようにしよう

Procを凍結できないかなぁ、と思いつつRHGを読んでいて気がついたこと。

Procオブジェクトの生成はかなり重い処理になる。Procオブジェクトを作るには、

  • マシンスタックに置いていたものを全部ヒープに移す
  • POPされても回収されないようにする

である。ここで、「全部」というのはprevまで含めて全部だ。そこに積んであ るスタックフレームを全部malloc()してコピーして複製を作る。VARSは普通だ とPOPと同時にrb_gc_force_recycle()で強制回収されるのだが、それも DVAR_DONT_RECYCLEフラグを付けて停止させる。などなどだ。実に思いきったことをする。

という処理を行う必要がある。

一方イテレータでは、この処理は必要ない。
だから、

def f()
  yield 42
end

def g(&block)
  block.call 42
end

よりも軽いことになる。

100,000回ループさせたところ、前者は0.4秒、後者は0.9秒だったのでだいたい倍近く違うことになる。

まあ、誤差の範囲で片付けられる程度だけれど、一応心に止めておこう。