【发布时间】:2011-04-23 14:01:10
【问题描述】:
发生了什么?有人可以解释一下这里发生了什么吗,我在紧密循环中改变了:
## 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)
注释的版本运行整个程序:625 ms,下一个生成器版本在时间运行整个程序2.125 秒。
这个更 Python 的版本导致性能如此灾难性的原因是什么?
编辑:可能是因为使用了 psyco 模块?当然,至少没有 psyco 的 Python 2.7 的运行时间是下一个版本的 2.141,这意味着与带有 psyco 的 Python 2.6 几乎相同。
删除 *.pyc 文件后,我没有得到放慢速度的代码。然后,当我也从库模块中删除了 psyco 的导入时,我得到了 2.6 的时间,也可以在没有 psyco 的情况下使用,非 psyco 版本和 psyco 版本的结果(因为现在库程序也变慢了,它的时间也相关:)
不是心理医生:
- 同时:图书馆准备:532 ms,总运行时间 2.625 s
- 下一步:在库中准备:532 毫秒, 总运行时间(time.clock()): 2.844 s(xrange 相同挂时的版本)
心理:
- 同时:图书馆准备:297 ms,总运行时间:609..675 ms
- 下一步:在库中准备:297 毫秒, 总运行时间: 1.922 秒(程序中到处都有范围而不是 xrange 的版本:1.985 秒)
在具有 2GB RAM 的 WindowsXP AMD Sempron 3100+ 系统中运行。用两个全局变量计算循环和调用:
j=i
callcount += 1
while j < ls - 1 and len(wordlist[j]) > lc:
j+=1
loopcount += 1
使用 psyco 测试输入的结果:
Finished in 625 ms
Loopcount: 78317
Callcount: 47970
Ration: 1.633
所以循环在紧密循环内,但平均只执行几次(请注意,全局计数器的两次增量并没有减慢 psyco 中的代码)
结论: 尽管算法相对于词汇长度的高度敏感,这导致我通过这个循环考虑了一些不可能的单词,但后来递归的基本情况通过字典查找检查,即 O(n),因此 非常有益的早期优化变得不是很有用,即使输入更长并且在函数开头移动调用计数计数器,表明调用计数不受词汇长度的影响,但外部循环计数被迅速减少(最初发布的代码在 if 语句的 elif 部分)。
更长的运行时间(29 372 个解决方案),同时删除了 while 循环和整个循环(使用 i 而不是 j)(库准备 312 毫秒):
- 无循环:elif 分支计数:485488,outerloopcount:10129147,比率:0,048,运行时间 6,000 秒(无计数器:4,594 秒)
- 有循环:循环计数:19355114,外部计数:8194033,比率:0,236,运行时间 5,704 秒(无计数器:4,688 秒)
(没有循环、计数器和 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**
【问题讨论】:
-
如果你真的想比较,你应该使用
xrange()。 -
没有 psyco 会发生这种情况吗?
-
第二个版本对我来说似乎并不像pythonic。
-
我无法重现您所看到的内容,尽管我不得不猜测
ls、lc和wordlist是什么以及您运行代码的频率.即便如此,Amber 对xrange()的建议完全有可能解决了这个问题。 (Amber 应该将其作为答案发布。)如果没有,您应该提供有关代码如何运行的更多信息。 -
根据 musicfreak 对我的回答的评论,您能否在禁用 Psyco 的情况下对此进行基准测试?此外,循环内的代码有多丰富(即我们在这里谈论多少次迭代)?随着迭代次数的增加,JIT 编译将倾向于提高性能。
标签: python optimization performance generator while-loop