27

在回答另一个问题时,我建议使用timeit来测试用正整数与负整数索引列表之间的区别。这是代码:

import timeit
t=timeit.timeit('mylist[99]',setup='mylist=list(range(100))',number=10000000)
print (t)
t=timeit.timeit('mylist[-1]',setup='mylist=list(range(100))',number=10000000)
print (t)

我用 python 2.6 运行了这段代码:

$ python2.6 test.py
0.587687015533
0.586369991302

然后我用 python 3.2 运行它:

$ python3.2 test.py
0.9212150573730469
1.0225799083709717

然后我挠了挠头,做了一点谷歌搜索,并决定在这里发布这些观察结果。

操作系统:OS-X (10.5.8) -- Intel Core2Duo

这对我来说似乎是一个非常显着的差异(超过 1.5 倍的差异)。有谁知道为什么 python3 这么慢 - 特别是对于这样一个常见的操作?

编辑

我在我的 Ubuntu Linux 桌面(Intel i7)上运行了相同的代码,并在 python2.6 和 python 3.2 上取得了可比的结果。这似乎是一个依赖于操作系统(或处理器)的问题(其他用户在 Linux 机器上看到了相同的行为——见评论)。

编辑 2

在其中一个答案中要求启动横幅,所以这里是:

Python 2.6.4 (r264:75821M, Oct 27 2009, 19:48:32) 
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin

和:

Python 3.2 (r32:88452, Feb 20 2011, 10:19:59) 
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin

更新

我刚刚从http://www.python.org/download/安装了新版本的 python2.7.3 和 python3.2.3

在这两种情况下,我都采取了

“Python xx3 Mac OS X 32 位 i386/PPC 安装程序(适用于 Mac OS X 10.3 到 10.6 [2])”

因为我在 OS X 10.5 上。以下是新的时间安排(通过多次试验相当一致):

蟒蛇2.7

$python2.7 test.py
0.577006101608
0.590042829514

蟒蛇3.2.3

$python3.2 test.py
0.8882801532745361
1.034242868423462
4

3 回答 3

24

这似乎是某些 Python 3.2 版本的产物。此时最好的假设是所有 32 位 Intel 版本都有减速,但没有 64 位版本。请继续阅读以了解更多详情。

您没有运行几乎足够的测试来确定任何事情。重复你的测试很多次,对于同一个测试,我得到的值从 0.31 到 0.54 不等,这是一个巨大的变化。

所以,我用10x数字和运行了你的测试repeat=10,使用了一堆不同的 Python2 和 Python3 安装。丢弃顶部和底部的结果,平均其他 8 个,然后除以 10(得到一个与您的测试等效的数字),这就是我所看到的:

 1. 0.52/0.53 Lion 2.6
 2. 0.49/0.50 Lion 2.7
 3. 0.48/0.48 MacPorts 2.7
 4. 0.39/0.49 MacPorts 3.2
 5. 0.39/0.48 HomeBrew 3.2

所以,看起来 3.2 实际上稍微快一点[99],和[-1].

但是,在 10.5 机器上,我得到了以下结果:

 1. 0.98/1.02 MacPorts 2.6
 2. 1.47/1.59 MacPorts 3.2

回到原来的(Lion)机器上,我在 32 位模式下运行,得到了这个:

 1. 0.50/0.48 Homebrew 2.7
 2. 0.75/0.82 Homebrew 3.2

因此,似乎 32 位才是最重要的,而不是 Leopard 与 Lion、gcc 4.0 与 gcc 4.2 或 clang、硬件差异等。这将有助于在 Leopard 下测试 64 位版本,使用不同的编译器等.,但不幸的是,我的 Leopard 盒子是第一代 Intel Mini(带有 32 位 Core Solo CPU),所以我无法进行该测试。

作为进一步的间接证据,我在 Lion 盒子上进行了一系列其他快速测试,看起来 32 位 3.2 比 2.x 慢了约 50%,而 64 位 3.2 可能比 2 快一点。 X。但如果我们真的想支持这一点,就需要有人挑选并运行一个真正的基准测试套件。

无论如何,此时我最好的猜测是,在优化 3.x 分支时,没有人在 32 位 i386 Mac 版本上投入太多精力。这实际上是他们做出的合理选择。

或者,或者,他们甚至没有在 32 位 i386 时期投入太多精力。这种可能性可以解释为什么 OP 在 linux 机器上看到 2.x 和 3.2 给出了相似的结果,而 Otto Allmendinger 在 linux 机器上看到 3.2 的速度与 2.6 相似。但由于他们都没有提到他们运行的是 32 位还是 64 位 linux,所以很难知道这是否相关。

我们还没有排除许多其他不同的可能性,但这似乎是最好的。

于 2012-07-09T18:24:18.240 回答
4

这是一个至少说明部分答案的代码:

$ python
Python 2.7.3 (default, Apr 20 2012, 22:44:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> t=timeit.timeit('mylist[99]',setup='mylist=list(range(100))',number=50000000)
>>> print (t)
2.55517697334
>>> t=timeit.timeit('mylist[99L]',setup='mylist=list(range(100))',number=50000000)
>>> print (t)
3.89904499054

$ python3
Python 3.2.3 (default, May  3 2012, 15:54:42) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> t=timeit.timeit('mylist[99]',setup='mylist=list(range(100))',number=50000000)
>>> print (t)
3.9906489849090576

python3 没有旧的 int 类型。

于 2012-07-09T20:14:38.090 回答
0

Python 3range()是 Python 2 xrange()。如果要range()在 Python 3 代码中模拟 Python 2,则必须使用list(range(num). 越大num,原始代码的差异就越大。

索引应该独立于列表中存储的内容,因为列表仅存储对目标对象的引用。引用是无类型的,并且都是相同的。因此,列表类型是一种同质的数据结构——从技术上讲。索引是指将索引值变成起始地址+偏移量。最多减去一次,计算偏移量非常有效。与其他操作相比,这是非常便宜的额外操作。

于 2012-07-09T22:24:11.557 回答