【发布时间】:2021-12-29 16:05:43
【问题描述】:
我一直在玩记忆和lru_cache...我有一个简短的问题,为什么我的记忆代码比lru_cache 运行得更好。
我的代码:
memo = {}
def fib(n):
if n == 0:
return 0
elif n < 2:
return 1
else:
if n not in memo:
memo[n] = fib(n-1) + fib(n-2)
return memo[n]
print(fib(900))
lru_cache 代码:
from functools import lru_cache
@lru_cache(maxsize=1000)
def fib(n):
if n == 0:
return 0
elif n < 2:
return 1
else:
return fib(n -1) + fib(n -2)
print(fib(499))
第二次尝试查找第 500 个 fib 编号时,我在 lru_cache 中收到以下错误:
lk/Documents/VSCode/testing_zone/fibonacci_examples/fib_with_lru_cache.py
Traceback (most recent call last):
File "c:\Users\lk\Documents\VSCode\testing_zone\fibonacci_examples\fib_with_lru_cache.py", line 14, in <module>
print(fib(500))
File "c:\Users\lk\Documents\VSCode\testing_zone\fibonacci_examples\fib_with_lru_cache.py", line 11, in fib
return fib(n -1) + fib(n -2)
File "c:\Users\lk\Documents\VSCode\testing_zone\fibonacci_examples\fib_with_lru_cache.py", line 11, in fib
return fib(n -1) + fib(n -2)
File "c:\Users\lk\Documents\VSCode\testing_zone\fibonacci_examples\fib_with_lru_cache.py", line 11, in fib
return fib(n -1) + fib(n -2)
[Previous line repeated 496 more times]
RecursionError: maximum recursion depth exceeded
然而,在我简单的 dict memoization 中,我可以在遇到同样的错误之前达到 900 个
lk/Documents/VSCode/testing_zone/fibonacci_examples/fib_with_memo.py
54877108839480000051413673948383714443800519309123592724494953427039811201064341234954387521525390615504949092187441218246679104731442473022013980160407007017175697317900483275246652938800
我的理解是 dict 和 lru_cache 的操作方式相同,它们引用 dict 或 lru_cache 在调用 fib(n) 函数之前查看 n 是否在其中。
我的问题是为什么他们的表现不一样?我是否错误配置了代码,或者是否需要与lru_cache 一起使用其他优化/代码?
lru_cache 必须正常工作,因为fib(400) 几乎是立即返回的,如果没有装饰器,则不会发生这种情况。
【问题讨论】:
-
能否提供计时状态?为什么你认为一个比另一个更好>
-
lru_cache名称中可能有提示 - 是的,它使用 dict 进行缓存,但它还会记录最近的使用情况,并在缓存已满后驱逐最少使用的条目。与不执行 lru 位的 functools.cache 进行比较。 -
@sahasrara62,我不认为一个比另一个更好。我的问题更多是关于为什么我可以使用 dict 方法计算几乎两倍的 fib(n) 900,而在遇到 RecursionError 之前使用 lru_cache 方法只能计算 499。引擎盖下一定发生了一些事情,我不知道,因为我的理解是它们的运作方式相同。干杯,利亚姆
-
@balmy Nah,即使使用
@lru_cache(maxsize=3),它在 n=500 左右也能正常工作。 -
@lru_cache装饰器将您的函数替换为检查缓存的包装函数,然后可能调用原始函数 - 因此堆栈上有 两个 函数调用fib()的每次实际调用。您的版本将缓存检查和实际操作合并到一个函数中,因此它消耗堆栈级别的速度减半。
标签: python python-3.x memoization