具有多次迭代的循环使执行速度异常缓慢
A loop with many iterations makes execution incredibly slow
此代码的执行时间约为 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)
为什么会这样?总迭代次数还是一样。
第二个示例处理的数字比第一个大得多(如@Sergii K 在上面评论的那样)。第二个示例代码可能会达到您系统上的最大 Fixnum 限制。在 32 位系统上,maximum signed integer is 2**(32-1) - 1 = 2147483647
which is much less than the maximum product j * prev
in the second example (as opposed to max products in the first example). In a situation like this ruby has to convert the Fixnums to Bignums 内部是第二个示例代码可能比第一个慢的原因。
在 64 位系统上,我希望两个样本大约同时 运行,因为最大的整数永远不会达到 Fixnum 限制。这就是为什么大多数其他评论者没有看到时间上有很大差异的原因。
Update:如果最大 Fixnum 数仅为 1073741823,如上面 OP 所评论,那么它必须意味着 OS 本身是 64 位也许安装的 ruby 也是 64 位 ruby,它仍然只使用 4 个字节来存储 Fixnum 数字(而不是真正的 64 位 rubies 中的 8 个)。最大整数值比第二个示例中需要的要少得多,因此它确实必须将较高的数字转换为 Bignums,这就是第二个示例的缓慢来源。
这个你自己对比一下就可以了:
(2**(0.size * 8 -2) -1).class # => Fixnum vs:
(2**(0.size * 8 -2) -1 + 1).class # => should be Bignum
此代码的执行时间约为 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)
为什么会这样?总迭代次数还是一样。
第二个示例处理的数字比第一个大得多(如@Sergii K 在上面评论的那样)。第二个示例代码可能会达到您系统上的最大 Fixnum 限制。在 32 位系统上,maximum signed integer is 2**(32-1) - 1 = 2147483647
which is much less than the maximum product j * prev
in the second example (as opposed to max products in the first example). In a situation like this ruby has to convert the Fixnums to Bignums 内部是第二个示例代码可能比第一个慢的原因。
在 64 位系统上,我希望两个样本大约同时 运行,因为最大的整数永远不会达到 Fixnum 限制。这就是为什么大多数其他评论者没有看到时间上有很大差异的原因。
Update:如果最大 Fixnum 数仅为 1073741823,如上面 OP 所评论,那么它必须意味着 OS 本身是 64 位也许安装的 ruby 也是 64 位 ruby,它仍然只使用 4 个字节来存储 Fixnum 数字(而不是真正的 64 位 rubies 中的 8 个)。最大整数值比第二个示例中需要的要少得多,因此它确实必须将较高的数字转换为 Bignums,这就是第二个示例的缓慢来源。
这个你自己对比一下就可以了:
(2**(0.size * 8 -2) -1).class # => Fixnum vs:
(2**(0.size * 8 -2) -1 + 1).class # => should be Bignum