我正在玩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个元素)的性能几乎相同?
答案 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指出的那样,类的初始化是在方法时序之外完成的,所以这不是少数条目上类似时序的原因。