怎么了?有人能解释一下这里发生了什么吗,我在紧密的循环中改变了:
## 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 毫秒 ,下生成器版本 在的时间运行了整个程序2.125 秒 .
这个更pythonic的版本导致性能如此灾难的原因是什么?
编辑:可能是使用 引起的psyco 模块 ?当然,至少没有 psyco 的 Python 2.7 的运行时间是下一个版本的 2.141,这意味着几乎与带有 psyco 的 Python 2.6 相同。
删除 *.pyc 文件后,我没有让代码变慢。然后,当我也从库模块中删除了 psyco 的导入时,我也得到了 2.6 计时也可以在没有 psyco 的情况下使用,非 psyco 版本和 psyco 版本的结果(因为现在库例程也变慢了,它的计时也很重要:)
不是精神病:
ms,总运行时间 2.625 秒
总运行时间(time.clock()):
2.844 秒(xrange 与墙时间相同的版本)
心理:
毫秒,总运行时间:609..675 毫秒
总运行时间:
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),因此 非常有益的早期优化变得不太有益 ,即使输入更长并且在函数的开头移动了 callcount 计数器,表明调用计数不受词汇长度的影响,但外循环计数略有减少(最初发布的代码在 if 语句的 elif 部分)。
更长的运行时间(29 372 个解决方案)使用 while 循环并删除整个循环(使用 i 而不是 j)(库准备 312 毫秒):
(无循环、计数器和 psyco 的运行时间:32,792 秒,库 608 毫秒)
所以没有额外的计数器 福利使用 psyco 的这个循环在更难的情况下:(4688-4594)*100/4688.0 % = 2%
这启发了我 反向另一个较早的优化 ,这是我在 DaniWeb 中想过的。早期版本的代码 跑得更快 ,当最小字长是全局的 ,不是参数。根据文档,局部变量调用更快,但显然使递归更重的成本超过了它。现在在更困难的情况下,另一个优化逆转带来了更多 案例中的预期性能行为 无字长优化:psyco 的运行时间为 312 ms 准备, 4,469..4,484 s 总运行时间 .因此,这使代码更清晰,并在这种情况下带来了更多好处,就像已删除的循环所具有的那样。并且用while循环把参数放到version,并没有太大的改变运行时间(库准备代码的变化变大了)
**What I learned from this: If you do n optimizations for speed
you must check the first n-1 optimizations after doing nth one**
最佳答案
我发现使用生成器通常比生成整个列表慢,这有点违反直觉。我仅通过添加 []
就设法解决了性能瓶颈。一对。
例如比较这些:
$ python -m timeit -n 1000 "' '.join(c for c in 'hello world')"
1000 loops, best of 3: 6.11 usec per loop
$ python -m timeit -n 1000 "' '.join([c for c in 'hello world'])"
1000 loops, best of 3: 3.79 usec per loop
即使对于如此简单的情况,首先生成整个列表的速度几乎是使用生成器的两倍!
编辑:正如 Thomas Wouters 在评论中指出的,这里的生成器速度较慢的原因是因为它是如此简单。为了平衡,这里是他的测试,其中生成器是明显的赢家:
$ python -m timeit -s "s = 'hello world' * 10000" -s "class C: pass" "for i in (C() for c in s): pass"
10 loops, best of 3: 33.6 msec per loop
$ python -m timeit -s "s = 'hello world' * 10000" -s "class C: pass" "for i in [C() for c in s]: pass"
10 loops, best of 3: 172 msec per loop
关于python - 将 while 转换为生成器的速度减慢了 3.4 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3902522/