Ruby 为什么array.min这么慢?

Ruby 为什么array.min这么慢?,ruby,performance,min,built-in,Ruby,Performance,Min,Built In,我注意到array.min似乎很慢,所以我针对自己的幼稚实现进行了此测试: require 'benchmark' array = (1..100000).to_a.shuffle Benchmark.bmbm(5) do |x| x.report("lib:") { 99.times { min = array.min } } x.report("own:") { 99.times { min = array[0]; array.each { |n| min = n if n <

我注意到
array.min
似乎很慢,所以我针对自己的幼稚实现进行了此测试:

require 'benchmark'
array = (1..100000).to_a.shuffle

Benchmark.bmbm(5) do |x|
  x.report("lib:") { 99.times { min = array.min } }
  x.report("own:") { 99.times { min = array[0]; array.each { |n| min = n if n < min } } }
end
我很震惊。我自己的实现如何通过
每个
运行一个块来击败内置的?比它赢了这么多

我是不是搞错了?还是这很正常?我很困惑


在Windows 8.1 Pro上运行的My Ruby版本:

C:\>ruby --version
ruby 2.2.3p173 (2015-08-18 revision 51636) [i386-mingw32]

如果您使用:

def my_min(ary)
  the_min = ary[0]
  i = 1
  len = ary.length
  while i < len
    the_min = ary[i] if ary[i] < the_min
    i += 1
  end
  the_min
end
def my_min(ary)
_min=ary[0]
i=1
len=ary.length
而我
如果ary[i]<
i+=1
结束
吴敏
结束
注意


我知道这不是一个答案,但我认为值得分享,并且将这段代码放到注释中会非常难看。

看看的实现。它可能最终使用
每个
循环遍历元素并获取min元素,但在此之前,它会进行一些额外的检查,查看是否需要返回多个元素,或者是否需要通过传递的块比较元素。在您的情况下,元素将通过函数进行比较,我怀疑这就是速度差异的来源——该函数比简单地比较两个数字要慢


对于阵列没有额外的优化,所有枚举都以相同的方式遍历。

对于那些喜欢升级到新版本软件的用户

require 'benchmark'
array = (1..100000).to_a.shuffle

Benchmark.bmbm(5) do |x|
  x.report("lib:") { 99.times { min = array.min } }
  x.report("own:") { 99.times { min = array[0]; array.each { |n| min = n if n < min } } }
end

Rehearsal -----------------------------------------
lib:    0.021326   0.000017   0.021343 (  0.021343)
own:    0.498233   0.001024   0.499257 (  0.499746)
-------------------------------- total: 0.520600sec

            user     system      total        real
lib:    0.018126   0.000000   0.018126 (  0.018139)
own:    0.492046   0.000000   0.492046 (  0.492367)

RUBY_VERSION # => "2.7.1"
需要“基准测试”
数组=(1..100000).to_a.shuffle
基准.bmbm(5)do|x|
x、 报告(“lib:”{99.times{min=array.min}
x、 报告(“own:”{99.times{min=array[0];array.each{n{124; min=n如果n“2.7.1”

如果你想用一种真正有效的方式来解决这个问题:O(log(n))或O(n),看看,我的结果完全不同,所以它们对你来说速度差不多。我仍然感到惊讶。你们有什么版本?我有2.2.2p95,现在将更新到2.3并再次测试。很有趣。如果这是Rubinius或JRuby,我会说这是一个积极优化的编译器,它正在做着令人敬畏的工作(特别是推测性内联),但是YARV根本没有做任何优化。从算法角度看,在查找
min
方面,你没有比O(n)更好的了,因为你别无选择,只能扫描每个元素。所以你的解决方案实际上是最优的。我猜在Ruby方法中,有一些额外的步骤会导致它们花费更长的时间。它实际上是
可枚举的#min
,而不是
数组#min
。因此,内置实现也必须使用
每个
。谢谢。我仍然认为编译的C比我的解释的Ruby快得多。但是看看这个
minu i
函数,我看到
OPTIMIZED\u CMP(i,memo->min,memo)<0
,如果我将自己的实现更改为使用
min=n if(n min)<0
,那么它至少会比内置的慢(在我的测试中大约8%)。我想我会就此罢休,只是哀悼如果我想快点,我必须自己用我的“漫长”之路去做……不知道你为什么要指出那些其他的事情,但是是的,很高兴看到图书馆的版本现在快多了:-)
require 'benchmark'
array = (1..100000).to_a.shuffle

Benchmark.bmbm(5) do |x|
  x.report("lib:") { 99.times { min = array.min } }
  x.report("own:") { 99.times { min = array[0]; array.each { |n| min = n if n < min } } }
end

Rehearsal -----------------------------------------
lib:    0.021326   0.000017   0.021343 (  0.021343)
own:    0.498233   0.001024   0.499257 (  0.499746)
-------------------------------- total: 0.520600sec

            user     system      total        real
lib:    0.018126   0.000000   0.018126 (  0.018139)
own:    0.492046   0.000000   0.492046 (  0.492367)

RUBY_VERSION # => "2.7.1"