具有多次迭代的循环使得执行速度极慢

时间:2016-05-31 09:10:26

标签: ruby loops execution-time

此代码的执行时间约为1秒:

start_time = Time.now

prev = 1
(1..1000).each do |i|
  (1..10000).each do |j|
    result = j * prev
    result = result + prev
    result = result - prev
    result = result / prev
    prev = j
  end
end

end_time = Time.now
printf('%f sec', end_time - start_time)

但是当我使用一个10000000次迭代的循环(而不是上面写的2个循环,1000次和10000次迭代)时,它会慢得多(大约4.5秒):

start_time = Time.now

prev = 1
(1..10000000).each do |j|
  result = j * prev
  result = result + prev
  result = result - prev
  result = result / prev
  prev = j
end

end_time = Time.now
printf('%f sec', end_time - start_time)

为什么会这样?总迭代次数仍然相同。

1 个答案:

答案 0 :(得分:2)

第二个示例处理的数字比第一个示例大得多(如上面评论的@Sergii K)。第二个示例代码可能达到系统上的最大Fixnum限制。在32位系统上,maximum signed integerj * prev,远小于第二个示例中的最大乘积(2**(0.size * 8 -2) -1).class # => Fixnum vs: (2**(0.size * 8 -2) -1 + 1).class # => should be Bignum (与第一个示例中的最大乘积相反)。在这种情况下,ruby必须在内部将Fixnums转换为Bignums,这就是为什么第二个示例代码可能比第一个示例代码慢。

在64位系统上,我希望两个样本大致同时运行,因为最大的整数永远不会达到Fixnum限制。这就是为什么大多数其他评论者可能没有看到时间上的巨大差异。

更新:如果最大Fixnum数字仅为1073741823,如上面的OP所评论,那么它必须意味着虽然操作系统本身是64位,也许安装的ruby也是64 -bit ruby​​,它仍然只使用4个字节来存储Fixnum数字(而不是真正的64位红宝石中的8个)。在第二个例子中,最大整数值要小得多,所以它确实必须将较高的数字转换为Bignums,这是第二个样本的缓慢来源。

如果你比较,你可以自己检查一下:

function sortArr($a, $b) {
    return intval(preg_replace('/[^0-9]+/', '', $a['id']), 10) - intval(preg_replace('/[^0-9]+/', '', $b['id']), 10) ; // it will extract number from string and compare it
}

usort($avaliableArray, 'sortArr');