其他答案非常彻底,Ruby中的Closures广泛涵盖了功能差异。我很好奇哪种方法对于可以接受块的方法最有效,所以我写了一些基准测试(参考Paul Mucur的文章)。我比较了三种方法:
- &阻止方法签名
- 使用
&Proc.new
- 包装
yield
在另一个块中
这是代码:
require "benchmark"
def always_yield
yield
end
def sometimes_block(flag, &block)
if flag && block
always_yield &block
end
end
def sometimes_proc_new(flag)
if flag && block_given?
always_yield &Proc.new
end
end
def sometimes_yield(flag)
if flag && block_given?
always_yield { yield }
end
end
a = b = c = 0
n = 1_000_000
Benchmark.bmbm do |x|
x.report("no &block") do
n.times do
sometimes_block(false) { "won't get used" }
end
end
x.report("no Proc.new") do
n.times do
sometimes_proc_new(false) { "won't get used" }
end
end
x.report("no yield") do
n.times do
sometimes_yield(false) { "won't get used" }
end
end
x.report("&block") do
n.times do
sometimes_block(true) { a += 1 }
end
end
x.report("Proc.new") do
n.times do
sometimes_proc_new(true) { b += 1 }
end
end
x.report("yield") do
n.times do
sometimes_yield(true) { c += 1 }
end
end
end
Ruby 2.0.0p247和1.9.3p392之间的性能相似。这是1.9.3的结果:
user system total real
no &block 0.580000 0.030000 0.610000 ( 0.609523)
no Proc.new 0.080000 0.000000 0.080000 ( 0.076817)
no yield 0.070000 0.000000 0.070000 ( 0.077191)
&block 0.660000 0.030000 0.690000 ( 0.689446)
Proc.new 0.820000 0.030000 0.850000 ( 0.849887)
yield 0.250000 0.000000 0.250000 ( 0.249116)
在&block
不经常使用的情况下添加显式参数确实会使该方法变慢。如果该块是可选的,则不要将其添加到方法签名中。而且,要在块之间传递,包裹yield
在另一个块中最快。
就是说,这些是一百万次迭代的结果,所以不必太担心。如果一种方法花费一秒钟的百万分之一来使代码更清晰,则无论如何都要使用它。