为啥 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.035f(10**7) 大约 0.35f(10**8) 大约 3.5f(10**9) 大约 35。但是f(10**10)?远远超过2000。这当然是出乎意料的。为什么迭代 10 倍的元素需要 60 倍以上的时间?导致这种情况的python for 循环是什么?这是特定于 python 的,还是在很多语言中都会出现这种情况?

【问题讨论】:

如果您使用python2,您正在创建一个列表,使用timeit模块您的时间也会更好 10**610**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 循环对于大输入如此非线性?的主要内容,如果未能解决你的问题,请参考以下文章

python中为啥我的for循环里嵌套的if只能循环一次?

为啥代码运行如此缓慢,以至于我在其中使用了 for 循环。有更快的方法吗?

为啥多处理会减慢嵌套的 for 循环?

Python:为啥弹出队列比 for-in 块更快?

python为啥for循环只查到一次数据

为啥for循环遍历python中的1个项目? [关闭]