13

別の質問に対するこの回答は、

array.map(&:to_s)

よりも速い

array.map { |n| n.to_s }

最初の例では、Procに&変わります。:to_s2番目の例では、ブロックを使用しています。

なぜProcはそのベンチマークのブロックよりも速いのでしょうか?この手法で通訳者が実行できる最適化はありますか?

4

3 に答える 3

5

それは実際には「proc vs block」ではありません。

以下は簡単な実験です (自由にコピーして実行してください)。

require 'benchmark'

many = 500
array = (1..10000).to_a

proc = proc { |a| a.to_s }

Benchmark.bm do |x|
  x.report('Symbol#to_proc') { many.times { array.map(&:to_s) } }
  x.report('proc') { many.times { array.map(&proc) }  }
  x.report('block') { many.times { array.map { |a| a.to_s } }  }
end

Ruby 1.9.3p194 の結果:

                user     system      total        real
Symbol#to_proc  1.170000   0.000000   1.170000 (  1.169055)
proc            1.450000   0.000000   1.450000 (  1.454216)
block           1.450000   0.000000   1.450000 (  1.448094)

ご覧のとおりblockprocどちらも事実上同じ量の CPU 時間を消費します。魔法はSymbol#to_procそれ自体の中にあります。

于 2012-07-14T06:22:30.450 に答える
4

Symbol#to_proc他の人が言っているように、これは一般的にprocsではなく具体的​​にであり、ほぼ確実にルビーの実装に依存しています。以前Symbol#to_procはルビー自体でしたが、それの純粋なルビーの実装は、同等のブロックよりも明らかに遅くなりました。

本当の答えを得るには、そのようなベンチマークを実行している間、ルビーのプロファイルを作成する必要があります。

私がrubyのソースコードを読んだところSymbol#to_proc、procを呼び出すと、少し特殊なものになります。procの本体は単なるC api呼び出し(rb_funcall_passing_block)ですが、それ以外の場合は、実際のrubyコードに少し時間がかかります。実行する。

于 2012-07-14T10:29:47.950 に答える
0

単なる推測ですが、おそらくそれは、Proc がブロックと同じように呼び出しのコンテキストを保持する必要がないためです。ブロックは、その外部で宣言された変数を知る必要がありますが、Proc は知りません。

于 2012-07-14T05:43:00.307 に答える