【发布时间】:2012-01-06 10:53:37
【问题描述】:
这是an answer I gave a few days back 的后续问题。 编辑:似乎该问题的 OP 已经使用我发布给他的代码询问 the same question,但我不知道。道歉。但是提供的答案不同!
我基本上观察到:
>>> def without_else(param=False):
... if param:
... return 1
... return 0
>>> def with_else(param=False):
... if param:
... return 1
... else:
... return 0
>>> from timeit import Timer as T
>>> T(lambda : without_else()).repeat()
[0.3011460304260254, 0.2866089344024658, 0.2871549129486084]
>>> T(lambda : with_else()).repeat()
[0.27536892890930176, 0.2693932056427002, 0.27011704444885254]
>>> T(lambda : without_else(True)).repeat()
[0.3383951187133789, 0.32756996154785156, 0.3279120922088623]
>>> T(lambda : with_else(True)).repeat()
[0.3305950164794922, 0.32186388969421387, 0.3209099769592285]
...或者换句话说:无论if 条件是否被触发,使用else 子句会更快。
我认为这与两者生成的不同字节码有关,但有人能够详细确认/解释吗?
编辑: 似乎不是每个人都能重现我的计时,所以我认为提供一些关于我的系统的信息可能会很有用。我正在运行安装了默认 python 的 Ubuntu 11.10 64 位。 python 生成以下版本信息:
Python 2.7.2+ (default, Oct 4 2011, 20:06:09)
[GCC 4.6.1] on linux2
以下是 Python 2.7 中的反汇编结果:
>>> dis.dis(without_else)
2 0 LOAD_FAST 0 (param)
3 POP_JUMP_IF_FALSE 10
3 6 LOAD_CONST 1 (1)
9 RETURN_VALUE
4 >> 10 LOAD_CONST 2 (0)
13 RETURN_VALUE
>>> dis.dis(with_else)
2 0 LOAD_FAST 0 (param)
3 POP_JUMP_IF_FALSE 10
3 6 LOAD_CONST 1 (1)
9 RETURN_VALUE
5 >> 10 LOAD_CONST 2 (0)
13 RETURN_VALUE
14 LOAD_CONST 0 (None)
17 RETURN_VALUE
【问题讨论】:
-
我现在找不到关于 SO 的相同问题。他们检查了生成的字节码,还有一个额外的步骤。观察到的差异非常依赖于测试人员(机器、SO..),有时只发现非常非常小的差异。
-
在 3.x 上,两者都生成 相同 字节码,但在
with_else末尾会保留一些无法访问的代码(LOAD_CONST(None); RETURN_VALUE- 但如前所述,从未达到)。我非常怀疑死代码会使函数更快。有人可以在 2.7 上提供dis吗? -
我无法重现这一点。
else和False的函数是最慢的(152ns)。第二快的是True,没有else(143ns),另外两个基本相同(137ns和138ns)。我没有使用默认参数,而是在 iPython 中用%timeit测量它。 -
我无法重现这些时间,有时 with_else 更快,有时这是 without_else 版本,看起来它们对我来说非常相似......
-
增加了反汇编的结果。我正在使用 Ubuntu 11.10、64 位、库存 Python 2.7 - 与 @mac 相同的配置。我也同意
with_else明显更快。
标签: python optimization python-2.7