是&;method(:method\u name)习惯用法对Ruby的性能有害?
我最近遇到了是&;method(:method\u name)习惯用法对Ruby的性能有害?,ruby,performance,Ruby,Performance,我最近遇到了方法(:method\u name)语法。(这使用了Object#methodmethod-)例如 [5, 7, 8, 1].each(&method(:puts)) 相当于 [5, 7, 8, 1].each{|number| puts number} 在Ruby的各种实现中,与前者相比,后者是否存在性能损失?如果是这样的话,实现者是否正在努力提高其性能?在最新的ruby 1.9.2上,他们看起来非常相似/相同 # Using ruby 1.9.2-p290 requ
方法(:method\u name)
语法。(这使用了Object#method
method-)例如
[5, 7, 8, 1].each(&method(:puts))
相当于
[5, 7, 8, 1].each{|number| puts number}
在Ruby的各种实现中,与前者相比,后者是否存在性能损失?如果是这样的话,实现者是否正在努力提高其性能?在最新的ruby 1.9.2上,他们看起来非常相似/相同
# Using ruby 1.9.2-p290
require 'benchmark'
Benchmark.measure do
1000.times { [5, 7, 8, 1].each(&method(:puts)) }
end
# => 0.020000 0.020000 0.040000 ( 0.066408)
# => 0.020000 0.010000 0.030000 ( 0.075474)
# => 0.020000 0.020000 0.040000 ( 0.048462)
Benchmark.measure do
1000.times { [5, 7, 8, 1].each{|number| puts number} }
end
# => 0.020000 0.020000 0.040000 ( 0.071505)
# => 0.020000 0.020000 0.040000 ( 0.062571)
# => 0.010000 0.020000 0.030000 ( 0.040944)
下面是一篇关于它的好文章(及时): 如果仔细看一下Mario答案中的分析数字,那么由于调用
Symbol\u proc
,额外的方法调用会受到轻微的惩罚
只是一个猜测,但我想说不,他们可能不会很快加快速度。是的,这似乎对性能不利
def time
start = Time.now
yield
"%.6f" % (Time.now - start)
end
def do_nothing(arg)
end
RUBY_VERSION # => "1.9.2"
# small
ary = *1..10
time { ary.each(&method(:do_nothing)) } # => "0.000019"
time { ary.each { |arg| do_nothing arg } } # => "0.000003"
# large
ary = *1..10_000
time { ary.each(&method(:do_nothing)) } # => "0.002787"
time { ary.each { |arg| do_nothing arg } } # => "0.001810"
# huge
ary = *1..10_000_000
time { ary.each(&method(:do_nothing)) } # => "37.901283"
time { ary.each { |arg| do_nothing arg } } # => "1.754063"
这似乎在JRuby中得到了解决:
$ rvm use jruby
Using /Users/joshuajcheek/.rvm/gems/jruby-1.6.3
$ xmpfilter f.rb
def time
start = Time.now
yield
"%.6f" % (Time.now - start)
end
def do_nothing(arg)
end
RUBY_VERSION # => "1.8.7"
# small
ary = *1..10
time { ary.each(&method(:do_nothing)) } # => "0.009000"
time { ary.each { |arg| do_nothing arg } } # => "0.001000"
# large
ary = *1..10_000
time { ary.each(&method(:do_nothing)) } # => "0.043000"
time { ary.each { |arg| do_nothing arg } } # => "0.055000"
# huge
ary = *1..10_000_000
time { ary.each(&method(:do_nothing)) } # => "0.427000"
time { ary.each { |arg| do_nothing arg } } # => "0.634000"
由于Rubinius是最先进、最积极地优化Ruby实现的工具,因此我选择了,并且: 我很遗憾地说,你认为它可能和一个街区一样的假设是完全错误的。您没有看到
Method#to_proc
的原因有二:
Proc
的方法的机制都是C语言,因此调用端的开销也是不可见的#method
返回一个method
对象,您必须查看该对象的内部并从中提取信息。在调用方面,在块内联的情况下,被调用的方法只能对块执行一些特殊的操作,这是一种只有Rubinius具有的优化
因此,要回答您的问题:
def time &block
start = Time.now
yield
puts "%s : %.6f" % block.to_s, (Time.now - start))
end
RUBY_VERSION # => "1.9.3-p327"
# small
ary = *1..10
time { ary.each(&:to_i) } # => "0.000010"
time { ary.each { |arg| arg.to_i } } # => "0.000002"
# large
ary = *1..10_000
time { ary.each(&:to_i) } # => "0.000494"
time { ary.each { |arg| arg.to_i } } # => "0.000798"
# huge
ary = *1..10_000_000
time { ary.each(&:to_i) } # => "0.504329"
time { ary.each { |arg| arg.to_i } } # => "0.883390"
该链接描述的是
&:foo
(调用object.foo
),而不是&方法(:foo)
(调用foo(object)
),对此表示抱歉。显然,它们不是同一个电话。不过还是一篇不错的文章!我在MRI 1.8的ruby prof评测中看到了Symbol#to_proc
(实现没有名字?),所以我不明白为什么Method#to_proc
不会出现。然而,这是将符号或方法转换为某种过程的开销。我怀疑上述过程的执行速度可能不同于普通块的执行速度:请参阅C中定义的关于评测方法的链接:我怀疑perftools的非Ruby版本可能能够做到这一点(即“评测Ruby VM和C扩展”).只是想知道最后两个问题的答案是否有变化?您的&:method(:dou\u nothing)
与do\u nothing arg
不太清楚您的意思。可能do\u nothing
方法在第一个方法中不接收参数,但在第二个方法中作为参数接收arg
。这有点不同,因为它调用的是绑定到对象的方法。