Aug*_*sta 22 python if-statement micro-optimization logical-operators python-2.7
一时兴起,我最近测试了这两种方法timeit,看看哪种评估方法更快:
import timeit
"""Test method returns True if either argument is falsey, else False."""
def and_chk((a, b)):
if not (a and b):
return True
return False
def not_or_chk((a, b)):
if not a or not b:
return True
return False
Run Code Online (Sandbox Code Playgroud)
......并得到了这些结果:
VALUES FOR a,b -> 0,0 0,1 1,0 1,1
method
and_chk(a,b) 0.95559 0.98646 0.95138 0.98788
not_or_chk(a,b) 0.96804 1.07323 0.96015 1.05874
...seconds per 1,111,111 cycles.
Run Code Online (Sandbox Code Playgroud)
效率的差异在1%到9%之间,总是有利于if not (a and b),这与我的预期相反,因为我理解if not a or not b它将按顺序评估其术语(if not a然后if not b),if一旦遇到真正的表达式就运行块(并且没有and条款).相反,该and_chk方法需要先评估两个子句,然后才能将任何结果返回给if not..包装子句.
然而,时间结果反驳了这种理解.那么,if评估的条件如何?我完全清楚这种程度的微观优化实际上,如果不是完全的话,毫无意义.我只是想了解Python是如何实现的.
为了完成,这就是我设置的方式timeit......
cyc = 1111111
bothFalse_and = iter([(0,0)] * cyc)
zeroTrue_and = iter([(1,0)] * cyc)
oneTrue_and = iter([(0,1)] * cyc)
bothTrue_and = iter([(1,1)] * cyc)
bothFalse_notor = iter([(0,0)] * cyc)
zeroTrue_notor = iter([(1,0)] * cyc)
oneTrue_notor = iter([(0,1)] * cyc)
bothTrue_notor = iter([(1,1)] * cyc)
time_bothFalse_and = timeit.Timer('and_chk(next(tups))', 'from __main__ import bothFalse_and as tups, and_chk')
time_zeroTrue_and = timeit.Timer('and_chk(next(tups))', 'from __main__ import zeroTrue_and as tups, and_chk')
time_oneTrue_and = timeit.Timer('and_chk(next(tups))', 'from __main__ import oneTrue_and as tups, and_chk')
time_bothTrue_and = timeit.Timer('and_chk(next(tups))', 'from __main__ import bothTrue_and as tups, and_chk')
time_bothFalse_notor = timeit.Timer('not_or_chk(next(tups))', 'from __main__ import bothFalse_notor as tups, not_or_chk')
time_zeroTrue_notor = timeit.Timer('not_or_chk(next(tups))', 'from __main__ import zeroTrue_notor as tups, not_or_chk')
time_oneTrue_notor = timeit.Timer('not_or_chk(next(tups))', 'from __main__ import oneTrue_notor as tups, not_or_chk')
time_bothTrue_notor = timeit.Timer('not_or_chk(next(tups))', 'from __main__ import bothTrue_notor as tups, not_or_chk')
Run Code Online (Sandbox Code Playgroud)
...然后运行每个timeit.Timer(..)函数.timeit(cyc)以获取结果.
skr*_*sme 27
除了两次跳转(在最坏的情况下),该not_or_chk函数还需要两个一元运算,而该函数只有两次跳转(在最坏的情况下).and_chk
该DIS模块来救援!该dis模块允许您查看代码的Python字节码反汇编.例如:
import dis
"""Test method returns True if either argument is falsey, else False."""
def and_chk((a, b)):
if not (a and b):
return True
return False
def not_or_chk((a, b)):
if not a or not b:
return True
return False
print("And Check:\n")
print(dis.dis(and_chk))
print("Or Check:\n")
print(dis.dis(not_or_chk))
Run Code Online (Sandbox Code Playgroud)
生成此输出:
And Check:
5 0 LOAD_FAST 0 (.0)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 1 (a)
9 STORE_FAST 2 (b)
6 12 LOAD_FAST 1 (a) * This block is the *
15 JUMP_IF_FALSE_OR_POP 21 * disassembly of *
18 LOAD_FAST 2 (b) * the "and_chk" *
>> 21 POP_JUMP_IF_TRUE 28 * function *
7 24 LOAD_GLOBAL 0 (True)
27 RETURN_VALUE
8 >> 28 LOAD_GLOBAL 1 (False)
31 RETURN_VALUE
None
Or Check:
10 0 LOAD_FAST 0 (.0)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 1 (a)
9 STORE_FAST 2 (b)
11 12 LOAD_FAST 1 (a) * This block is the *
15 UNARY_NOT * disassembly of *
16 POP_JUMP_IF_TRUE 26 * the "not_or_chk" *
19 LOAD_FAST 2 (b) * function *
22 UNARY_NOT
23 POP_JUMP_IF_FALSE 30
12 >> 26 LOAD_GLOBAL 0 (True)
29 RETURN_VALUE
13 >> 30 LOAD_GLOBAL 1 (False)
33 RETURN_VALUE
None
Run Code Online (Sandbox Code Playgroud)
看一下我用星号标记的两个Python字节码块.这些块是你的两个反汇编函数.请注意,and_chk只有两次跳转,并且在决定是否进行跳转时进行函数计算.
另一方面,除了解释器是否进行跳转之外,该not_or_chk功能还要求not在最坏的情况下执行两次操作.
| 归档时间: |
|
| 查看次数: |
3635 次 |
| 最近记录: |