【问题标题】:Why Python works faster when declaring integer variable with int()?为什么用 int() 声明整数变量时 Python 工作得更快?
【发布时间】:2018-03-21 23:27:27
【问题描述】:

在编写仅使用整数算术的算法时,我注意到 Python 没有利用它。

于是我尝试了下面的代码,看看“显式”声明的效果

import time

repeat = 1000000

start = time.time()
x = 0
for i in range(repeat):
    x += 1
no_type_time = time.time() - start

start = time.time()
y = int(0)
for i in range(repeat):
    y += 1
int_time = time.time() - start

print('{} - No type'.format(no_type_time))
print('{} - Int'.format(int_time))

代码输出如下:

0.0692429542542 - No type
0.0545210838318 - Int

我认为这与 Python 作为一种动态类型语言有关。但是当我尝试找出变量的类型时,使用 type(x) 和 type(y) 都输出 int。这很奇怪,因为我还使用 x = float(0) 进行了一些测试,结果非常接近没有类型“声明”的结果。

我想知道为什么会这样,如果可能的话,我想从解释它的 Python 文档中获得一些参考。

【问题讨论】:

  • 这根本不是计时执行的方法。您应该查看timeit 等。在执行期间您的系统上可能发生了任何影响资源的事情。
  • Python 2 还是 Python 3?这听起来与显式调用int 没有任何关系;这听起来像是你在看一个混杂因素,比如 Python 2 上range(repeat) 中涉及的分配。

标签: python performance typing dynamic-typing


【解决方案1】:

根据str.format 输出中浮点数的精度(12 位有效数字),我们可以看出您可能使用的是 Python 2。

当您运行range(repeat) 时,Python 2 会创建一个包含一百万个整数的显式列表,这很慢。它还保留了所有这些整数的内存,因此 range(repeat) 第二次的速度较慢。这很可能是时间差异的来源,与调用 int 无关。

在 Python 2 上,使用 xrange 而不是 range 几乎总是更好。 xrange 按需生成整数,避免了预先生成整个列表的内存成本和分配时间:

for i in xrange(repeat):
    do_stuff()

【讨论】:

  • 谢谢,我想你已经发现了 OP 的问题。
  • 也许建议如何用xrange修复它?
  • 这也可以解释为什么正确的timeit 不能重现问题——每次都通过timeit 循环,但首先是重用 obheap 空闲列表中的内存。
  • 假设 OP 的结果是可重复的(可能是也可能不是),那么这应该可以通过颠倒测试的顺序来轻松验证。此外,OP 可以简单地将 range(repeat) 分配给所有时间之外的变量并使用它。
  • @abarnert: xrange 已添加。
【解决方案2】:

我无法在 linux 上重现。 标记:

• 真实:从开始到结束运行流程所花费的实际时间,就好像它是由人用秒表测量的一样

• user:计算过程中所有CPU所花费的累计时间

• sys:所有 CPU 在内存分配等系统相关任务期间所花费的累计时间。

→ time python type.py

real    0m0.219s
user    0m0.000s
sys     0m0.000s

→ time python without_type.py

real    0m0.133s
user    0m0.000s
sys     0m0.000s

【讨论】:

    【解决方案3】:

    这是因为 python 缓存并重用了一些不可变的内置对象,即使它们被“存储”为不同的变量

    >>> a = 1
    >>> id(a)
    56188528L
    >>> b = int(1)
    >>> id(b)
    56188528L
    

    Python 不必为第二个变量分配任何内存或实例化新对象。它只是重用了已经创建的不可变整数对象。

    如果您将计时测试放在不同的文件中并分别运行它们,或者如果您先运行 int(1) 测试,您会看到不同的结果。

    【讨论】:

    • 没有。 x=0 使用的是预先构建的常量; y=int(0) 使用相同的常量,然后查找全局并调用它。那里没有再利用。此外,为单个 int 分配内存没什么。问题是range 返回的百万项目列表。构建需要一段时间,但分配和构建需要更长的时间。不同的是,第一次,它必须分配;第二次,之前创建并收集的列表中存在内存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 2014-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多