【问题标题】:Python3 vs Python2 list/generator range performancePython3 与 Python2 列表/生成器范围性能
【发布时间】:2014-06-18 02:54:34
【问题描述】:

我有一个简单的函数,它对列表进行分区并返回列表中的索引 i,使得索引小于 i 的元素小于 list[i] 并且索引大于 i 的元素更大。

def partition(arr):
    first_high = 0
    pivot = len(arr) - 1
    for i in range(len(arr)):
        if arr[i] < arr[pivot]:
            arr[first_high], arr[i] = arr[i], arr[first_high]
            first_high = first_high + 1

    arr[first_high], arr[pivot] = arr[pivot], arr[first_high]
    return first_high


if __name__ == "__main__":
    arr = [1, 5, 4, 6, 0, 3]
    pivot = partition(arr)
    print(pivot)

python 3.4 的运行时间比 python 2.7.6 大得多 在 OS X 上:

time python3 partition.py
real 0m0.040s
user 0m0.027s
sys  0m0.010s

time python partition.py
real 0m0.031s
user 0m0.018s
sys  0m0.011s

在 ubuntu 14.04 / virtual box 上也是如此

python3:

real 0m0.049s
user 0m0.034s
sys  0m0.015s

蟒蛇:

real 0m0.044s
user 0m0.022s
sys  0m0.018s

python3 本身是否比 python2.7 慢,或者是否对代码进行了任何特定优化,使其运行速度与在 python2.7 上一样快

【问题讨论】:

  • 使用timeit模块比较代码执行,而不是time; Python 启动时间过多,随机操作系统事件(如磁盘刷新)也是如此。
  • 我在尝试您的代码时意识到,lasthigh 是什么?由于lasthigh 未初始化,开箱即用的代码将失败?请查看。
  • @PauloBu 你是对的。没有lasthigh 它实际上是first_high。固定的谢谢。

标签: python performance python-2.7 python-3.x generator


【解决方案1】:

如 cmets 中所述,您应该使用 timeit 而不是操作系统工具进行基准测试。

我的猜测是range 函数在 Python 3 中的执行速度可能会慢一些。在 Python 2 中它只返回一个 list,在 Python 3 中它返回一个 range,其行为或多或少类似于生成器。我做了一些基准测试,结果是这样的,这可能暗示了你正在经历的事情:

python -mtimeit "range(10)"
1000000 loops, best of 3: 0.474 usec per loop

python3 -mtimeit "range(10)"
1000000 loops, best of 3: 0.59 usec per loop

python -mtimeit "range(100)"
1000000 loops, best of 3: 1.1 usec per loop

python3 -mtimeit "range(100)"
1000000 loops, best of 3: 0.578 usec per loop

python -mtimeit "range(1000)"
100000 loops, best of 3: 11.6 usec per loop

python3 -mtimeit "range(1000)"
1000000 loops, best of 3: 0.66 usec per loop

如您所见,当提供给 range 的输入时,它在 Python 2 中往往会很快。如果输入增长,那么 Python 3 的 range 表现更好。 p>

我的建议:测试较大数组的代码,包含一百或一千个元素。

实际上,我更进一步,通过元素测试了一个完整的迭代。结果完全支持 Python 2:

python -mtimeit "for i in range(1000):pass"
10000 loops, best of 3: 31 usec per loop

python3 -mtimeit "for i in range(1000):pass"
10000 loops, best of 3: 45.3 usec per loop

python -mtimeit "for i in range(10000):pass"
1000 loops, best of 3: 330 usec per loop

python3 -mtimeit "for i in range(10000):pass"
1000 loops, best of 3: 480 usec per loop

我的结论是,遍历列表可能比遍历生成器更快。尽管后者在内存消耗方面肯定更有效。这是速度和内存之间权衡的经典示例。虽然速度差异本身并没有那么大(小于毫秒)。因此,您应该重视这一点以及什么对您的程序更好。

【讨论】:

  • 我不在电脑旁,所以无法检查,但我认为您应该尝试使用非常大的数字(例如 1000 万到 10 亿)进行第二个基准测试。我假设 Python 2 的 range 执行的前期分配将在极限情况下扼杀性能。
  • Python 3 实现似乎针对非常大的范围进行了优化!感谢您的回答。
  • Python 3 range() 应该与 Python 2 xrange() 进行比较。它不会首先生成列表,它只会遍历值。这样,它也不会为更大的范围消耗更多的内存。
  • 可以优化循环列表,因为元素的数量是预先知道的。实际上,循环不需要被StopIteration 异常停止——这样循环不需要测试是否发生异常(更简单的代码)。但这只是我的猜测。
  • 使用 Python 2 的十亿整数范围会爆炸内存,因为它需要大约 4GB 来存储列表。这正是 Python3 的 range 或 Python2 的 xrange 派上用场的时候。我在答案中提到的那种权衡。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-18
  • 1970-01-01
  • 2020-05-25
  • 2014-11-22
  • 2017-04-06
  • 2018-07-05
  • 2019-04-24
相关资源
最近更新 更多