为什么[]比list()快? [英] Why is [] faster than list()?
问题描述
我最近比较了[]
和list()
的处理速度,并惊讶地发现[]
运行的速度比list()
高出三倍.我对{}
和dict()
进行了相同的测试,结果实际上是相同的:[]
和{}
都花费了约0.128sec/百万个周期,而list()
和dict()
花费了约0.428sec/百万每个循环.
I recently compared the processing speeds of []
and list()
and was surprised to discover that []
runs more than three times faster than list()
. I ran the same test with {}
and dict()
and the results were practically identical: []
and {}
both took around 0.128sec / million cycles, while list()
and dict()
took roughly 0.428sec / million cycles each.
这是为什么?立即执行[]
和{}
(也可能是()
和''
),同时传回一些空股票文字的副本,同时使用它们的显式命名副本(list()
,dict()
,tuple()
, str()
)完全创建对象,无论它们实际上是否包含元素?
Why is this? Do []
and {}
(and probably ()
and ''
, too) immediately pass back a copies of some empty stock literal while their explicitly-named counterparts (list()
, dict()
, tuple()
, str()
) fully go about creating an object, whether or not they actually have elements?
我不知道这两种方法有何不同,但我很想找出答案. 我在文档中或SO上都找不到答案,而寻找空括号却比我预期的要麻烦得多.
I have no idea how these two methods differ but I'd love to find out. I couldn't find an answer in the docs or on SO, and searching for empty brackets turned out to be more problematic than I'd expected.
我分别通过调用timeit.timeit("[]")
和timeit.timeit("list()")
以及timeit.timeit("{}")
和timeit.timeit("dict()")
来比较列表和字典,以获得计时结果.我正在运行Python 2.7.9.
I got my timing results by calling timeit.timeit("[]")
and timeit.timeit("list()")
, and timeit.timeit("{}")
and timeit.timeit("dict()")
, to compare lists and dictionaries, respectively. I'm running Python 2.7.9.
我最近发现"为什么True慢于if 1? ",将if True
与if 1
的性能进行比较,似乎触及了类似的从字面量到全局的情况;也许也值得考虑.
I recently discovered "Why is if True slower than if 1?" that compares the performance of if True
to if 1
and seems to touch on a similar literal-versus-global scenario; perhaps it's worth considering as well.
推荐答案
因为[]
和{}
是文字语法. Python可以创建字节码仅用于创建列表或字典对象:
Because []
and {}
are literal syntax. Python can create bytecode just to create the list or dictionary objects:
>>> import dis
>>> dis.dis(compile('[]', '', 'eval'))
1 0 BUILD_LIST 0
3 RETURN_VALUE
>>> dis.dis(compile('{}', '', 'eval'))
1 0 BUILD_MAP 0
3 RETURN_VALUE
list()
和dict()
是单独的对象.它们的名称需要解析,必须包含堆栈以推入参数,必须存储框架以供以后检索,并且必须进行调用.所有这些都需要更多时间.
list()
and dict()
are separate objects. Their names need to be resolved, the stack has to be involved to push the arguments, the frame has to be stored to retrieve later, and a call has to be made. That all takes more time.
对于空的情况,这意味着您至少有一个 LOAD_NAME
(必须搜索全局名称空间以及 __builtin__
模块),后跟 CALL_FUNCTION
,它必须保留当前帧:
For the empty case, that means you have at the very least a LOAD_NAME
(which has to search through the global namespace as well as the __builtin__
module) followed by a CALL_FUNCTION
, which has to preserve the current frame:
>>> dis.dis(compile('list()', '', 'eval'))
1 0 LOAD_NAME 0 (list)
3 CALL_FUNCTION 0
6 RETURN_VALUE
>>> dis.dis(compile('dict()', '', 'eval'))
1 0 LOAD_NAME 0 (dict)
3 CALL_FUNCTION 0
6 RETURN_VALUE
您可以使用timeit
分别计时名称查找:
You can time the name lookup separately with timeit
:
>>> import timeit
>>> timeit.timeit('list', number=10**7)
0.30749011039733887
>>> timeit.timeit('dict', number=10**7)
0.4215109348297119
时间差异可能是字典哈希冲突.从调用这些对象的时间中减去这些时间,然后将结果与使用文字的时间进行比较:
The time discrepancy there is probably a dictionary hash collision. Subtract those times from the times for calling those objects, and compare the result against the times for using literals:
>>> timeit.timeit('[]', number=10**7)
0.30478692054748535
>>> timeit.timeit('{}', number=10**7)
0.31482696533203125
>>> timeit.timeit('list()', number=10**7)
0.9991960525512695
>>> timeit.timeit('dict()', number=10**7)
1.0200958251953125
因此,每调用1000万个对象,调用该对象将花费额外的1.00 - 0.31 - 0.30 == 0.39
秒.
So having to call the object takes an additional 1.00 - 0.31 - 0.30 == 0.39
seconds per 10 million calls.
您可以通过将全局名称别名为本地名称来避免全局查找成本(使用timeit
设置,绑定到名称的所有内容都是本地名称):
You can avoid the global lookup cost by aliasing the global names as locals (using a timeit
setup, everything you bind to a name is a local):
>>> timeit.timeit('_list', '_list = list', number=10**7)
0.1866450309753418
>>> timeit.timeit('_dict', '_dict = dict', number=10**7)
0.19016098976135254
>>> timeit.timeit('_list()', '_list = list', number=10**7)
0.841480016708374
>>> timeit.timeit('_dict()', '_dict = dict', number=10**7)
0.7233691215515137
但您永远无法克服CALL_FUNCTION
的费用.
but you never can overcome that CALL_FUNCTION
cost.
这篇关于为什么[]比list()快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!