为什么[]比list()快?

  • 问题:
  • 我最近比较了[]list()的处理速度,惊讶地发现[]list()快三倍多。我用{}dict()进行了相同的测试,结果几乎完全相同:[]{}都花费了0.128秒/百万个周期,而list()dict()每个周期大约为0.428秒/百万个周期

    为什么会这样?当显式命名的对应对象(list()dict()tuple()str())完全着手创建对象时,[[/code>和)元素?在

    我不知道这两种方法有什么不同,但我很想知道。

    我通过调用时间!时间(“[])时间!时间(“list()”,和时间!时间(“{}”)时间!时间(“dict()”,分别比较列表和字典。我运行的是python2.7.9

    我最近发现“Why is if True slower than if 1?“这将if Trueif 1的性能进行了比较,似乎触及了类似的文字与全局场景;或许这也值得考虑

  • 答案:
  • 因为[]{}文本语法。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()是单独的对象。它们的名称需要被解析,堆栈必须被用于推送参数,帧必须被存储以便稍后检索,并且必须进行调用。这需要更多的时间

    对于空箱子,这意味着你至少有一个LOAD_NAME(它必须搜索全局命名空间以及内置模块后接a调用函数,必须保留当前帧:

    >>> 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分别为名称查找计时:

    >>> 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

    通过将全局名称别名为局部名称,可以避免全局查找开销(使用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

    但你永远无法克服这个调用函数的成本