【问题标题】:Why is Python 3.1 slower than 2.6 for this code?为什么此代码的 Python 3.1 比 2.6 慢?
【发布时间】:2011-03-14 10:43:53
【问题描述】:

考虑以下代码(来自here,随着测试数量的增加):

from timeit import Timer

def find_invpow(x,n):
    """Finds the integer component of the n'th root of x,
    an integer such that y ** n <= x < (y + 1) ** n.
    """
    high = 1
    while high ** n < x:
        high *= 2
    low = high/2
    while low < high:
        mid = (low + high) // 2
        if low < mid and mid**n < x:
            low = mid
        elif high > mid and mid**n > x:
            high = mid
        else:
            return mid
    return mid + 1

def find_invpowAlt(x,n):
    """Finds the integer component of the n'th root of x,
    an integer such that y ** n <= x < (y + 1) ** n.
    """
    low = 10 ** (len(str(x)) / n)
    high = low * 10
    while low < high:
        mid = (low + high) // 2
        if low < mid and mid**n < x:
            low = mid
        elif high > mid and mid**n > x:
            high = mid
        else:
            return mid
    return mid + 1

x = 237734537465873465
n = 5
tests = 1000000

print "Norm", Timer('find_invpow(x,n)', 'from __main__ import find_invpow, x,n').timeit(number=tests)
print "Alt", Timer('find_invpowAlt(x,n)', 'from __main__ import find_invpowAlt, x,n').timeit(number=tests)

使用 Python 2.6 (Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) [GCC 4.4.3] on linux2),报告的时间为:

Norm 9.73663210869
Alt 9.53973197937

但是,在使用 Python 3.1 (Python 3.1.2 (r312:79147, Apr 15 2010, 15:35:48) [GCC 4.4.3] on linux2) 的同一台机器上,时间是:

Norm 28.4206559658
Alt 26.8007400036

有谁知道为什么这段代码在 Python 3.1 上运行速度要慢三倍?

【问题讨论】:

  • no repro:python3.1 在我的机器上比 2.6 快大约 30%。
  • 谢谢。你在运行什么操作系统?我在 Ubuntu 10.04 64 位上得到了上述时间。
  • 同系统32位版本
  • @Paul Baker:我在 Mac OS X 64 位(但使用 Python 3.1.1 32 位而不是 3.1.2)上的数字几乎与您相同。
  • @Paul:这些不是相同的代码,你忘了from __future__ import division,没有一个,结果是不同的。虽然我不完全确定这是导致此问题的原因,但我怀疑它可能是。

标签: python performance python-3.x


【解决方案1】:

从 2.5、2.6、2.7 和 3.1 (Windows XP SP2) 开始,使用“/”版本的时间逐渐减少。使用 //,3.1 倍显着小于 2.X 倍,例如“标准”从 6.35 (py2.7) 降至 3.62 (py3.1)。

请注意,在 2.x 中,有整数(机器字,32 或 64 位)和长整数(可变长度)。在 3.x 中,long 已重命名为 int,而 int 消失了。我的猜测是,从 long 转换为 float 可能会导致 / 的额外时间。

无论如何,一个更好的“Alt”版本将从以下代码开始:

high = 1
highpown = 1
while highpown < x:
    high <<= 1
    highpown <<= n

【讨论】:

  • “将以该代码 ... 开始”。后跟low = high // 2?
  • @Paul Baker:当然。 low = high / 2 是两个函数中的一个 BUG。
  • +1。我强烈怀疑是intlong 方面有所不同。请注意,在 32 位机器上,正在测试的值不适合 int,因此您将在 Python 2.x 和 3.x 中使用 long 进行计算。但在 64 位机器上,您在 2.x 中使用 int 算术,在 3.x 中使用任意精度算术。
【解决方案2】:

// 运算符在 python 2 和 3 中执行整数除法(或下限除法),而/ 运算符在给定整数操作数的 Python 2 中执行下除法,在给定任何操作数的情况下在 python 3 中执行真除法。

尝试将/ 运算符替换为// 运算符。

【讨论】:

  • 谢谢。我将low = high/2 替换为low = high//2,将low = 10 ** (len(str(x)) / n) 替换为low = 10 ** (len(str(x)) // n)。这使得from __future__ import division 的 2.6 性能与 2.6 的常规性能一致。不幸的是,3.1 的性能没有改变 - 仍然比 2.6 慢 3 倍。
  • 当然,问题在于python3中的“整数”是python2的旧“长”。运营商在这里无关紧要:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-10
  • 2012-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多