Ton*_*nen 11 python optimization performance generator while-loop
怎么了?有人可以解释一下这里发生了什么,我在紧密循环中改变了:
## j=i
## while j < ls - 1 and len(wordlist[j]) > lc: j+=1
j = next(j for j in range(i,ls) if len(wordlist[j]) <= lc)
Run Code Online (Sandbox Code Playgroud)
评论的版本运行整个程序:625毫秒,下一个生成器版本在2.125秒的时间内运行整个程序.
有什么理由可以说这个更加pythonic的版本会导致性能上的这种灾难?
编辑:也许它是由使用psyco模块引起的?当然至少没有psyco的Python 2.7的运行时间对于下一个版本来说是2.141,意味着与使用psyco的Python 2.6几乎相同.
删除*.pyc文件后,我得到的代码没有减速.然后,当我从库模块中删除了psyco的导入时,我还得到了2.6时序,没有psyco使用,非psyco版本和psyco版本的结果(现在库例程也慢了,它的时间也相关:)
不是psyco:
Psyco是:
在带有2GB RAM的WindowsXP AMD Sempron 3100+系统中运行.使用两个全局变量计算循环和调用:
j=i
callcount += 1
while j < ls - 1 and len(wordlist[j]) > lc:
j+=1
loopcount += 1
Run Code Online (Sandbox Code Playgroud)
使用psyco进行测试输入的结果:
Finished in 625 ms
Loopcount: 78317
Callcount: 47970
Ration: 1.633
Run Code Online (Sandbox Code Playgroud)
因此循环在紧密循环内,但平均只执行几次(注意两个增量的全局计数器没有减慢psyco中的代码)
结论: 尽管算法相对于词汇长度具有高度敏感性,这导致我通过此循环考虑传递一些不可能的词,后来通过字典查找检查递归的基本情况,即O(n),因此高度有益的早期优化变得不是很有用,即使输入较长并且在函数开头移动callcount计数器,也表明调用计数不受词汇长度的影响,但是外部循环计数被切片减少(最初发布的代码是elif部分if语句).
使用while循环运行时间更长(29 372个解决方案)并删除整个循环(使用i代替j)(库准备312 ms):
(没有循环,计数器和psyco的运行时间:32,792秒,库608毫秒)
因此,如果没有额外的计数器,使用psyco的循环的好处是更难的情况:(4688-4594)*100/4688.0%= 2%
这激发了我扭转另一个早期的优化,我在DaniWeb中想到了这个优化.早期版本的代码运行得更快,当最小的字大小是全局的,而不是参数.根据文档记录,局部变量调用更快,但显然使递归的成本更重.现在在更难的情况下,在没有优化字长的情况下,优化的另一个逆转带来了更多预期的性能行为:使用psyco的运行时间为312毫秒准备,总计4,469 ... 4,484秒的运行时间.因此,这使得代码更清晰,并且在这种情况下带来了更多的好处,因为已删除的循 并且将参数放入带有while循环的版本,并没有太多改变运行时间(库编写代码的变化变大)
**What I learned from this: If you do n optimizations for speed
you must check the first n-1 optimizations after doing nth one**
Run Code Online (Sandbox Code Playgroud)
两者并不等同。
j=i
while j < ls - 1 and len(wordlist[j]) > lc:
j+=1
Run Code Online (Sandbox Code Playgroud)
一旦 wordlist[j] <= lc 就会停止 while 循环。如果列表中的第一个单词短于或等于 lc,则可以想象它会执行循环零次。
j = next(j for j in range(i,ls) if len(wordlist[j]) <= lc)
Run Code Online (Sandbox Code Playgroud)
将继续迭代 i 到 ls 的整个范围,无论列表中单词的长度如何。
编辑:忽略上面的内容 - 正如 Amber 指出的那样,对 next() 的调用意味着生成器表达式仅在返回第一个结果之前进行求值。在这种情况下,我怀疑时间差异来自于使用 range() 而不是 xrange() (除非这是 Python 3.x)。在 Python 2.x 中,range() 将在内存中创建完整列表,即使生成器表达式仅返回第一个值。