我注意到一個小的重構,在遞歸函數中用一個調用內建的max
替換了一個循環,造成了一個奇怪的性能。爲什麼max(iterable)的執行速度比等效循環慢得多?
這裏的簡單重現,我可以產生:
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)
它沒有memoization實現,所以有一個指數數量的調用。
使用max(iterable)
的實現比具有循環的實現慢兩倍以上。
奇怪的是,
(編輯:沒關係,請參閱@TimPeters答案)。另外,如果我使用max
vs loop的直接比較沒有證明效果
max(a, b)
而不是max(iterable)
,則性能不匹配會消失。
這個性能差距與您在(1,2)'中傳遞給'max':max(f2(nk)* n)的生成器表達式有關。生成器在空間優化和發電機需要暫停並繼續,直到它們完全耗盡,這種暫停/恢復是一個很大的性能損失 – direprobs
@MosesKoledoye問題在於,這可能是機器對機器的不同形式,一般來說,發電機 – direprobs
@direprobs無論哪種方式,即使沒有gen也可以使'max'版本更低。exp。 –