【发布时间】:2020-05-17 14:14:49
【问题描述】:
当你只有一把锤子时,一切看起来都像钉子。所以可以说 Ruby 中的Array#each 方法,在发现Array#map 和Array#select 和其他可迭代方法的实用性、优雅性和语法乐趣之前。我很好奇的是:
为什么在使用更精确的可迭代方法时性能会有所提高?一般情况下是这样吗?
例如,在
require 'benchmark'
array = (1..100000).to_a
puts Benchmark.measure {
100.times do
array.map { |el| el.even? }
end
}
puts Benchmark.measure {
100.times do
new_array = []
array.each do |el|
new_array << el.even?
end
end
}
# ruby bench.rb
# 0.450598 0.015524 0.466122 ( 0.466802)
# 0.496796 0.018525 0.515321 ( 0.516196)
Benchmark 总是显示出有利于Array#map 的时间性能差异。在以下代码中:
puts Benchmark.measure {
100.times do
array.select { |el| el.even? }
end
}
puts Benchmark.measure {
100.times do
new_array = []
array.each do |el|
if el.even?
new_array << el
end
end
end
}
# ruby bench.rb
# 0.405254 0.007965 0.413219 ( 0.413733)
# 0.471416 0.008875 0.480291 ( 0.481079)
Array#select 每次都胜过杰里操纵的 Array#each。
那么,为什么这些更精确的方法会产生明显更好的性能呢?这是 Ruby 和/或所有语言中的通用公理吗?
【问题讨论】:
-
FWIW,在您的第二个示例中,
new_array将比 map 返回的数组大 100 倍,并在您的基准测试完成运行时选择,因为它不会在运行。不知道这是否会导致性能差异,但您可能需要检查一下。 -
我认为我们可以得出结论,专用方法总是比以特定方式使用的更通用方法更快(或至少不慢),原因很简单,前者是对后者进行封装,Ruby 的核心方法编写者努力优化性能。我想有人可能会争辩说,出于内存考虑,某些核心方法可能不会针对速度进行优化,但它们仍然会针对某些性能指标进行优化,因此在相同的指标上,它们不会比经过调整的通用方法更差。
-
不应该将
new_array = []放在100.times块内以获得相同的结果吗?您目前正在比较 2 个不同的任务。 -
天啊!感谢您的提醒。固定!
标签: ruby performance