为什么array.min这么慢?

时间:2022-06-12 04:09:33

I noticed that array.min seems slow, so I did this test against my own naive implementation:

我注意到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

The results:

结果:

Rehearsal -----------------------------------------
lib:    1.531000   0.000000   1.531000 (  1.538159)
own:    1.094000   0.016000   1.110000 (  1.102130)
-------------------------------- total: 2.641000sec

            user     system      total        real
lib:    1.500000   0.000000   1.500000 (  1.515249)
own:    1.125000   0.000000   1.125000 (  1.145894)

I'm shocked. How can my own implementation running a block via each beat the built-in? And beat it by so much?

我感到震惊。我自己的实现如何通过每个块运行一个块击败内置?并且打败了这么多?

Am I somehow mistaken? Or is this somehow normal? I'm confused.

我有点错吗?或者这是不正常的?我很困惑。


My Ruby version, running on Windows 8.1 Pro:

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

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

2 个解决方案

#1


2  

Have a look at the implementation of Enumerable#min. It might use each eventually to loop through the elements and get the min element, but before that it does some extra checking to see if it needs to return more than one element, or if it needs to compare the elements via a passed block. In your case the elements will get to be compared via min_i function, and I suspect that's where the speed difference comes from - that function will be slower than simply comparing two numbers.

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

There's no extra optimization for arrays, all enumerables are traversed the same way.

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

#2


1  

It's even faster if you use:

如果你使用它会更快:

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

NOTE

注意

I know this is not an answer, but I thought it was worth sharing and putting this code into a comment would have been exceedingly ugly.

我知道这不是一个答案,但我认为值得分享并将此代码放入评论中会非常难看。

#1


2  

Have a look at the implementation of Enumerable#min. It might use each eventually to loop through the elements and get the min element, but before that it does some extra checking to see if it needs to return more than one element, or if it needs to compare the elements via a passed block. In your case the elements will get to be compared via min_i function, and I suspect that's where the speed difference comes from - that function will be slower than simply comparing two numbers.

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

There's no extra optimization for arrays, all enumerables are traversed the same way.

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

#2


1  

It's even faster if you use:

如果你使用它会更快:

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

NOTE

注意

I know this is not an answer, but I thought it was worth sharing and putting this code into a comment would have been exceedingly ugly.

我知道这不是一个答案,但我认为值得分享并将此代码放入评论中会非常难看。