Ruby:Proc#调用vs yield
什么是以下两种实现方式之间Ruby中的行为差异thrice
方法?
module WithYield
def self.thrice
3.times { yield } # yield to the implicit block argument
end
end
module WithProcCall
def self.thrice(&block) # & converts implicit block to an explicit, named Proc
3.times { block.call } # invoke Proc#call
end
end
WithYield::thrice { puts "Hello world" }
WithProcCall::thrice { puts "Hello world" }
“行为差异”包括错误处理,性能,工具支持等。
我认为第一个实际上是另一个的语法糖。 换句话说,没有行为差异。
第二种形式允许的是将该块“保存”在变量中。 然后可以在其他时间点调用该块 - 回调。
好。 这次我去做了一个快速的基准测试:
require 'benchmark'
class A
def test
10.times do
yield
end
end
end
class B
def test(&block)
10.times do
block.call
end
end
end
Benchmark.bm do |b|
b.report do
a = A.new
10000.times do
a.test{ 1 + 1 }
end
end
b.report do
a = B.new
10000.times do
a.test{ 1 + 1 }
end
end
b.report do
a = A.new
100000.times do
a.test{ 1 + 1 }
end
end
b.report do
a = B.new
100000.times do
a.test{ 1 + 1 }
end
end
end
结果很有趣:
user system total real
0.090000 0.040000 0.130000 ( 0.141529)
0.180000 0.060000 0.240000 ( 0.234289)
0.950000 0.370000 1.320000 ( 1.359902)
1.810000 0.570000 2.380000 ( 2.430991)
这表明使用block.call比使用yield要慢两倍。
不同类型的红宝石瓶盖之间的行为差异已被广泛记录
这是Ruby 2.x的更新
ruby 2.0.0p247(2013-06-27修订版41674)[x86_64-darwin12.3.0]
我厌倦了手动编写基准测试,所以我创建了一个名为benable的小亚军模块
require 'benchable' # https://gist.github.com/naomik/6012505
class YieldCallProc
include Benchable
def initialize
@count = 10000000
end
def bench_yield
@count.times { yield }
end
def bench_call &block
@count.times { block.call }
end
def bench_proc &block
@count.times &block
end
end
YieldCallProc.new.benchmark
产量
user system total real
bench_yield 0.930000 0.000000 0.930000 ( 0.928682)
bench_call 1.650000 0.000000 1.650000 ( 1.652934)
bench_proc 0.570000 0.010000 0.580000 ( 0.578605)
我认为这里最令人惊讶的是bench_yield
比bench_proc
慢。 我希望我多了解一下为什么会发生这种情况。