我最近比较了 和 的处理速度,[]惊讶list()地发现它的[]运行 速度 比list(). 我用{}and进行了相同的测试,dict()结果几乎相同:[]两者{}都花费了大约 0.128 秒 / 百万个周期,而list()每个dict()大约花费了 0.428 秒 / 百万个周期。
[]
list()
{}
dict()
为什么是这样?[]和{}(可能()和,''也可能)立即传回一些空的股票文字的副本,而它们的明确命名的对应物(list(), dict(), tuple(), str())完全开始创建一个对象,无论它们是否真的有元素?
()
''
tuple()
str()
我不知道这两种方法有何不同,但我很想知道。我在文档或 SO 上找不到答案,而且搜索空括号的问题比我预期的要严重。
timeit.timeit("[]")我通过调用and timeit.timeit("list()")、 andtimeit.timeit("{}")和timeit.timeit("dict()"), 分别比较列表和字典来得到我的计时结果。我正在运行 Python 2.7.9。
timeit.timeit("[]")
timeit.timeit("list()")
timeit.timeit("{}")
timeit.timeit("dict()")
我最近发现了“为什么 if True 比 if 1 慢? ”它比较了if Trueto的性能,if 1似乎触及了类似的文字与全局场景;也许它也值得考虑。
if True
if 1
因为[]and{}是 字面语法 。Python 可以创建字节码来创建列表或字典对象:
>>> 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()是单独的对象。需要解析它们的名称,必须涉及堆栈以推送参数,必须存储框架以供以后检索,并且必须进行调用。这一切都需要更多时间。
对于空的情况,这意味着您至少有 a LOAD_NAME(必须搜索全局命名空间以及builtinsmodule)后跟 a CALL_FUNCTION,它必须保留当前帧:
LOAD_NAME
builtins
CALL_FUNCTION
>>> 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:
timeit
>>> import timeit >>> timeit.timeit('list', number=10**7) 0.30749011039733887 >>> timeit.timeit('dict', number=10**7) 0.4215109348297119
时间差异可能是字典哈希冲突。从调用这些对象的时间中减去这些时间,并将结果与使用文字的时间进行比较:
>>> 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秒数。
1.00 - 0.31 - 0.30 == 0.39
您可以通过将全局名称别名为本地名称来避免全局查找成本(使用timeit设置,您绑定到名称的所有内容都是本地名称):
>>> 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成本。