Ruby每个vs while循环性能

时间:2015-09-17 10:41:43

标签: ruby performance while-loop each

试图在Ruby中解决算法的基本问题,并测试性能。

以防万一,该算法旨在找到可被1到20之间的所有数字整除的最小正数。 这是代码:

def remainder(number) # with while
  divisor = 2
  while divisor < 21
    return false unless number % divisor == 0
    divisor += 1
  end
  true
end

def remainder(number) # with each
  (2..20).each do |divisor|
    return false unless number % divisor == 0
  end
  true
end

number = 180_000_000
while number < 10_000_000_000
  if remainder number
    puts "#{number}"
    break
  end
  number += 1
end

在我的计算机上,使用while版本,Ruby大约需要10秒,每个版本需要70到80秒才能解决。代码完全相同,给出相同的结果。为什么性能会有这么差异?

2 个答案:

答案 0 :(得分:5)

似乎成本增加了:

  1. 创建范围对象的枚举器(2..20)
  2. each
  3. 中调用块

    这是一个基准

    require 'benchmark'
    
    c = 100_000
    Benchmark.bm(7) do |x|
      x.report("range - 1 :") { c.times { (2..20) } }
      x.report("range - 2 :") { c.times { (2..20).each } }
      x.report("range - 3 :") { c.times { (2..20).each { |x| x } } }
    end
    

    上面的示例输出是:

                  user     system      total        real
    range - 1 :  0.000000   0.000000   0.000000 (  0.006004)
    range - 2 :  0.031000   0.000000   0.031000 (  0.026017)
    range - 3 :  0.125000   0.000000   0.125000 (  0.122081)
    [Finished in 0.4s]
    

    可以看出,创建Range对象不是问题,但为它创建枚举器会增加时间,并将块传递给该迭代器并执行一些代码会增加成本。

    与此相比,while循环实现正在进行基本操作。因此,更快。

    请注意,for循环的效果与each一样糟糕,因为它或多或少等同于each实施

答案 1 :(得分:1)

each是一种方法,它使用while循环在C中使用for 实现,其中(在C中)执行你while循环做同样的事情。在内部,它需要持有一个计数器,将其初始化为2并将其增加到20 - 这与while版本需要做的事情相同。但是each版本也有创建函数(块)的开销,将其发送到each方法,并在for循环内的each循环的每次迭代中调用它。 1}}方法的实现。所有这些都需要计算机的额外工作,这使得代码变慢。