Python deque性能适用于小型迭代

时间:2010-01-16 12:50:23

标签: python performance deque

我正在玩Python的collection.deque,并编写了以下基准:

#!/usr/bin/python

import timeit

if __name__=='__main__':
    number = 1000000
    for r in (1,10,100,1000,5000,10000,100000):
        print r
        print timeit.timeit("while x: x.pop(0);",
                            "x = list(range("+str(r)+"))",
                            number=number)
        print timeit.timeit("while x: x.popleft();",
                            "from collections import deque; x = deque(range("+str(r)+"))",
                             number=number)

这将从具有各种大小的列表/双端队列中弹出(0)/ popleft()。结果是:

1
0.0801048278809
0.0822219848633
10
0.081041097641
0.080836057663
100
0.0806250572205
0.0807700157166
1000
0.081248998642
0.082062959671
5000
0.0976719856262
0.0825741291046
10000
0.157499074936
0.0825819969177
100000
16.0247170925
0.097559928894

我的问题是:为什么小型deques和列表(~1000个元素)的性能几乎相同?

3 个答案:

答案 0 :(得分:4)

timeit模块运行一次设置代码,然后运行定时代码number次(在这种情况下,number == 1000000)。在您的情况下,这看起来像(对于列表情况):

x = list(range(r))
#timer is started here
for iteration in xrange(1000000):
    while x: x.pop(0)
#timer is stopped here

正如您所看到的,只有第一次迭代才能执行任何操作,而其他999999次迭代只检查x的大小,因为它将为空。此检查将花费大约相同的时间用于列表和deques。

对于小的列表/ deques,第一次迭代相对于其他999999次迭代组合很短,所以你并没有真正测量任何相关的东西,并得到相似的时间。

如果您使用number==1,则不会出现此问题。另一个选择是让定时代码按下并弹出一个项目,以便列表/双端队列保持相同的大小。

答案 1 :(得分:3)

我总是发现timeit更适合在shell命令行中使用。在这里,例如:

$ python -mtimeit -s'from collections import deque; base=range(100); ctr=list' 'x=ctr(base)' 'while x: x.pop(0)'
10000 loops, best of 3: 77.3 usec per loop
$ python -mtimeit -s'from collections import deque; base=range(100); ctr=deque' 'x=ctr(base)' 'while x: x.popleft()'
10000 loops, best of 3: 36 usec per loop

所需的预防措施(在循环外进行导入,在循环中创建数据的新副本)更容易查看和实现,这样......

答案 2 :(得分:2)

对于数量较少的元素,构造双端队列和列表所需的时间很长。

一旦数字f元素增长,这在结果中就不再重要了。

重写测试,以便列表的构造超出了timeit调用。

编辑:正如@Interjar指出的那样,类的初始化是在方法时序之外完成的,所以这不是少数条目上类似时序的原因。