列出索引效率(python 2 vs python 3)

时间:2012-07-09 17:58:33

标签: python performance indexing osx-leopard

在回答另一个question时,我建议使用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 x.x.3 Mac OS X 32位i386 / PPC安装程序(适用于Mac OS X 10.3到10.6 [2])”

因为我在OS X 10.5上。以下是新时间(通过多次试验合理一致):

python 2.7

$python2.7 test.py
0.577006101608
0.590042829514

python 3.2.3

$python3.2 test.py
0.8882801532745361
1.034242868423462

3 个答案:

答案 0 :(得分:24)

这似乎是Python 3.2的一些版本的工件。在这一点上,最好的假设是所有32位英特尔版本都有减速,但没有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

因此,使用[99]看起来3.2实际上稍快一点,与[-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 vs. 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看到2.x和3.2在linux盒子上给出类似的结果,而Otto Allmendinger看到3.2在linux盒子上同样慢到2.6。但由于他们都没有提到他们是在运行32位还是64位Linux,因此很难知道这是否相关。

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

答案 1 :(得分: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类型。

答案 2 :(得分:0)

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

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