为啥 python 的 for 循环对于大输入如此非线性?
Posted
技术标签:
【中文标题】为啥 python 的 for 循环对于大输入如此非线性?【英文标题】:Why are python's for loops so non-linear for large inputs?为什么 python 的 for 循环对于大输入如此非线性? 【发布时间】:2015-04-24 02:12:47 【问题描述】:我在对一些 python 代码进行基准测试时发现了一些奇怪的东西。我使用以下函数来测量遍历一个空的 for 循环所需的速度:
def f(n):
t1 = time.time()
for i in range(n):
pass
print(time.time() - t1)
f(10**6)
打印大约 0.035
、f(10**7)
大约 0.35
、f(10**8)
大约 3.5
和 f(10**9)
大约 35
。但是f(10**10)
?远远超过2000
。这当然是出乎意料的。为什么迭代 10 倍的元素需要 60 倍以上的时间?导致这种情况的python for 循环是什么?这是特定于 python 的,还是在很多语言中都会出现这种情况?
【问题讨论】:
如果您使用python2,您正在创建一个列表,使用timeit模块您的时间也会更好 从10**6
到10**9
有很大的不同。 指数增长
那么我认为这是因为 10^9 适合标准的 32 位整数,而 10^10 python 使用任意大小的整数。这会使每次比较都变慢。
也许python为列表分配内存。对于太多项目,操作系统正在分页到磁盘空间。
@clemos24 不在 Py3 中,range
返回一个生成器,而不是一个列表。
【参考方案1】:
当您超过10^9
时,您将超出 32 位整数范围。然后,Python3 会透明地将您移动到 arbitrary precision integers,它的分配和使用速度要慢得多。
一般来说,处理如此大的数字是 Python3 比 Python2 慢得多的领域之一(在许多系统上至少有快速的 64 位整数)。从好的方面来说,它使 python 更易于使用,overflow 类型错误更少。
【讨论】:
它以 Pep237: python.org/dev/peps/pep-0237 开头,这使得 longs 具有任意精度。后来 Python3 摆脱了导致速度变慢的 int 类型。在 3.x 版本中,我相信他们一直在努力为更小的整数引入更多优化。 运行时间的实际差异似乎完全是特定于平台的。 @PadraicCunningham 我一直在尝试阅读长期实现的源代码,以确切了解何时进行了哪些优化。一个数字应该是 15 位还是 30 位当然是有选择的,但在那之后,解密这一切就变成了很多工作。【参考方案2】:使用timeit
的一些准确计时显示时间实际上随着输入大小而大致增加,因此您的计时似乎还有很长的路要走:
In [2]: for n in [10**6,10**7,10**8,10**9,10**10]:
% timeit f(n)
...:
10 loops, best of 3: 22.8 ms per loop
1 loops, best of 3: 226 ms per loop # roughly ten times previous
1 loops, best of 3: 2.26 s per loop # roughly ten times previous
1 loops, best of 3: 23.3 s per loop # roughly ten times previous
1 loops, best of 3: 4min 18s per loop # roughly ten times previous
使用 xrange 和 python2 我们看到比率大致相同,显然 python2 总体上要快得多,因为 python3 int 已被 long 取代:
In [5]: for n in [10**6,10**7,10**8,10**9,10**10]:
% timeit f(n)
...:
100 loops, best of 3: 11.3 ms per loop
10 loops, best of 3: 113 ms per loop
1 loops, best of 3: 1.13 s per loop
1 loops, best of 3: 11.4 s per loop
1 loops, best of 3: 1min 56s per loop
运行时间的实际差异似乎与 window's long 的大小更相关,而不是与 python 3 直接相关。当使用处理 long 与 windows 大不相同的 unix 时,差异是微不足道的,所以这是一个特定于平台的问题和蟒蛇一样多。
【讨论】:
我只是跑了另一个测试,我得到了以下结果:10**7
- 3.4924984秒,@ - 3.492617328秒,@ - 34.7125293306957秒,@ - 34.71252936832384秒,@ 987654330@ - 2190.0514266665177 秒。我们在哪个系统上运行它会有所不同吗?
@user3002473。你在用什么运行它?
@PadriacCunningham Windows 7 64 位,安装了 4.00 GB RAM 的 Intel Core i5 3.20 GHz 处理器。
@user3002473。我在具有类似规格的 Ubuntu 14.04 上。我想不出它运行如此缓慢的任何明显原因。您是否尝试过将 python 2 与 xrange 一起使用?
@user3002473,你受到窗口大小的限制,***.com/questions/384502/… 所以你得到了OverflowError
。与 mu linux 机器相比,这可能是导致性能如此差的一个因素。明天我会做更多的挖掘,因为整个整数大小的解释并不能解释整个故事。如果它是特定于 python 的,我应该有类似的性能影响以上是关于为啥 python 的 for 循环对于大输入如此非线性?的主要内容,如果未能解决你的问题,请参考以下文章