Amr*_*Amr 6 python optimization loops
有时我必须检查一些在循环内没有变化的条件,这意味着在每次迭代中都会对测试进行评估,但我认为这不是正确的方法.
我认为,因为条件在循环内部没有变化,我应该只在循环外测试一次,但是我必须"重复自己"并且可能不止一次地写同一个循环.这是一个显示我的意思的代码:
#!/usr/bin/python
x = True #this won't be modified inside the loop
n = 10000000
def inside():
for a in xrange(n):
if x: #test is evaluated n times
pass
else:
pass
def outside():
if x: #test is evaluated only once
for a in xrange(n):
pass
else:
for a in xrange(n):
pass
if __name__ == '__main__':
outside()
inside()
Run Code Online (Sandbox Code Playgroud)
cProfile在前面的代码上运行给出了以下输出:
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.542 0.542 0.542 0.542 testloop.py:5(inside)
1 0.261 0.261 0.261 0.261 testloop.py:12(outside)
1 0.000 0.000 0.803 0.803 testloop.py:3(<module>)
Run Code Online (Sandbox Code Playgroud)
这表明,显然,在循环外进行一次测试可以提供更好的性能,但是我必须编写两次相同的循环(如果有一些elifs 则可能更多).
我知道,这样的表现也不会在大多数情况下无所谓,但我需要知道什么是写这种代码的最好方式.例如,有没有办法告诉python只评估一次测试?
任何帮助表示赞赏,谢谢.
实际上,经过一些测试后,我现在确信性能上的差异主要受到循环内执行的其他代码的影响,而不是测试的评估.所以现在我坚持使用第一种形式,它更具可读性,更适合以后的调试.
首先,示例之间性能差异的一个主要组成部分是查找全局的时间.如果我们将其捕获到局部变量中:
def inside_local():
local_x = x
for a in xrange(n):
if local_x:
pass
else:
pass
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.258 0.258 0.258 0.258 testloop.py:13(outside)
1 0.314 0.314 0.314 0.314 testloop.py:21(inside_local)
1 0.421 0.421 0.421 0.421 testloop.py:6(inside)
Run Code Online (Sandbox Code Playgroud)
大部分性能差异消失了.
通常,只要有公共代码,就应该尝试封装它.如果if除了循环之外没有任何共同点,则尝试将循环迭代器封装到例如发生器中.
这是我在这种情况下通常做的事情.
def inside():
def x_true(a):
pass
def x_false(a):
pass
if x:
fn = x_true
else:
fn = x_false
for a in xrange(n):
fn(a)
Run Code Online (Sandbox Code Playgroud)