【问题标题】:Why is the ternary operator faster then .get for dicts?为什么三元运算符比 .get 更快?
【发布时间】:2017-12-20 21:28:45
【问题描述】:

我最近发现了一些令人惊讶的事情。给定不包含键 k 的字典 d,使用三元运算符尝试检索具有默认返回的项目:

>>> def tern():
...     d[k] if k in d else 'foo'
...
>>> timeit.timeit(tern, number=1000000)
0.12342095375061035

运行速度比 dict 的 .get() 函数快:

>>> def get_meth():
...     d.get(k, 'foo')
...
>>> timeit.timeit(get_meth, number=1000000)
0.20549297332763672

这对我来说似乎违反直觉。我认为三元运算符需要通过 dict 进行 2 次搜索(一次用于测试 k in d),然后再进行一次以检索 d[k],而 .get 将简单地尝试检索 d[k],如果失败,则返回'foo'.

我在一个大字典(一百万个元素)和一个小字典(100 个)上都运行了这个,而且这两次,三进制都明显更快。这里的幕后发生了什么?

【问题讨论】:

  • 你多久打一次else
  • "给定一个不包含密钥 k 的字典 d",所以每次
  • 鉴于密钥永远不会在您的测试中的字典中,因此您的三元表达式的 d[k] 部分永远不会执行。因此,在任何一种情况下都只进行一次查找。剩下的就是在d.get()另一个字典查找:必须在包含d 方法的字典中查找属性“get”。
  • 设置m = d.get,把函数体改成m(k, 'foo'),你会看到很大的不同
  • 好的,有趣的结果:设置m=d.get 和运行当前项目都仍然有三元优于get

标签: python python-2.7 dictionary


【解决方案1】:

如果你反汇编这两种方法,你会发现get 有一个额外的CALL_FUNCTION,与POP_JUMP_IF_FALSE 指令相比,这在python 中是昂贵的。

如果在

  3           0 LOAD_CONST               1 ('blub')
              3 LOAD_GLOBAL              0 (d)
              6 COMPARE_OP               6 (in)
              9 POP_JUMP_IF_FALSE       22
             12 LOAD_GLOBAL              0 (d)
             15 LOAD_CONST               1 ('blub')
             18 BINARY_SUBSCR       
             19 JUMP_FORWARD             3 (to 25)
        >>   22 LOAD_CONST               2 ('foo')
        >>   25 POP_TOP             
             26 LOAD_CONST               0 (None)
             29 RETURN_VALUE        

获取方法:

  6           0 LOAD_GLOBAL              0 (d)
              3 LOAD_ATTR                1 (get)
              6 LOAD_CONST               1 ('blub')
              9 LOAD_CONST               2 ('foo')
             12 CALL_FUNCTION            2          #Expensive call
             15 POP_TOP             
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

前段时间我读过一篇很长的文章,其中有一段描述了为什么CALL_FUNCTION 如此昂贵: https://doughellmann.com/blog/2012/11/12/the-performance-impact-of-using-dict-instead-of-in-cpython-2-7-2/

【讨论】:

  • 如果对象的 __contains__ 没有在 C 中实现(我猜是 dict 的?)COMPARE_OP... 的成本会相似吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-06
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2015-08-17
  • 2011-03-22
  • 2018-01-15
相关资源
最近更新 更多