【发布时间】:2017-06-17 17:36:50
【问题描述】:
我注意到一个小的重构对性能造成了奇怪的影响,该重构用递归函数内的内置 max 调用替换了循环。
这是我能制作的最简单的复制品:
import time
def f1(n):
if n <= 1:
return 1
best = 0
for k in (1, 2):
current = f1(n-k)*n
if current > best:
best = current
return best
def f2(n):
if n <= 1:
return 1
return max(f2(n-k)*n for k in (1, 2))
t = time.perf_counter()
result1 = f1(30)
print('loop:', time.perf_counter() - t) # 0.45 sec
t = time.perf_counter()
result2 = f2(30)
print('max:', time.perf_counter() - t) # 1.02 sec
assert result1 == result2
f1 和 f2 都使用标准递归计算阶乘,但添加了不必要的最大化(这样我就可以在递归中使用 max,同时仍然保持递归简单):
# pseudocode
factorial(0) = 1
factorial(1) = 1
factorial(n) = max(factorial(n-1)*n, factorial(n-2)*n)
它是在没有记忆的情况下实现的,因此调用次数呈指数级增长。
使用max(iterable) 的实现比使用循环的慢两倍以上。
奇怪的是,(编辑:没关系,请参阅@TimPeters 的回答)。另外,如果我使用max 与循环的直接比较并没有证明效果max(a, b) 而不是max(iterable),性能不匹配就会消失。
【问题讨论】:
-
这种性能差距与您传递给
max:max(f2(n-k)*n for k in (1, 2)的生成器表达式有关。生成器在空间优化方面表现良好,但在速度方面表现不佳。发电机需要暂停并继续,直到它们完全耗尽。这种暂停/恢复对性能造成很大影响。 -
@MosesKoledoye 问题是,这可能是不同形式的机器。一般来说,生成器往往很慢,它们必须暂停然后恢复工作。
-
@direprobs 不管怎样,
max版本仍然较低,即使没有 gen。 exp. -
@MosesKoledoye 有趣。我还没有测试过,我对生成器进行了一些测试,与
for循环进行了比较。
标签: python performance python-3.x python-internals