python - 为什么Python斐波那契序列循环比递归慢?

标签 python python-3.x memoization timeit

下面是著名的斐波那契数列示例

# test.py
import sys
sys.setrecursionlimit(20000)

def fib_loop(n):
    if n <= 1:
        return n
    fn, fnm1 = 1, 0
    for _ in range(2, n+1):
        fn, fnm1 = fn + fnm1, fn
    return fn

def fib_recursion(n, memo={}):
    if n <= 1:
        return n
    if n not in memo:
        memo[n] = fib_recursion(n-1, memo) + fib_recursion(n-2, memo)
    return memo[n]

正如大家一样,我曾经认为循环变体会比递归变体快得多。然而,实际结果却让人大吃一惊。

$ python3 -m timeit "import test; test.fib_loop(10000)"
100 loops, best of 5: 1.93 msec per loop
$ python3 -m timeit "import test; test.fib_recursion(10000)"
500000 loops, best of 5: 471 nsec per loop

我不知道为什么。有人可以帮助我吗?

最佳答案

因为您正在记住您的结果。并且您在每次迭代中都会重复使用该备忘录。所以第一次运行速度很慢。在所有其他调用中,它都是一个简单的字典查找。

如果您使用number=1,因此它只运行一次,您会发现第一次调用实际上更慢

>>> import sys
>>> sys.setrecursionlimit(20000)
>>>
>>> def fib_loop(n):
...     if n <= 1:
...         return n
...     fn, fnm1 = 1, 0
...     for _ in range(2, n+1):
...         fn, fnm1 = fn + fnm1, fn
...     return fn
...
>>> def fib_recursion(n, memo={}):
...     if n <= 1:
...         return n
...     if n not in memo:
...         memo[n] = fib_recursion(n-1, memo) + fib_recursion(n-2, memo)
...     return memo[n]
...
>>> import timeit
>>> timeit.timeit("fib_loop(1000)", setup="from __main__ import fib_loop", number=1)
9.027599999456015e-05
>>> timeit.timeit("fib_recursion(1000)", setup="from __main__ import fib_recursion", number=1)
0.0016194200000114733

或者,如果您为每个外部调用传递一个新的备忘录字典,您会得到相同的行为:

>>> timeit.timeit("fib_recursion(1000, {})", setup="from __main__ import fib_recursion", number=1000)
0.38679519899999093
>>> timeit.timeit("fib_loop(1000)", setup="from __main__ import fib_loop", number=1000)
0.07079556799999409

关于python - 为什么Python斐波那契序列循环比递归慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65697411/

相关文章:

python - Python 中的正则表达式大括号

Python3.8 JSON 模块在 Ubuntu 20.04 LTS 上不起作用

python-3.x - 在 redis-py 中, redis.StrictRedis.pipe 线程安全吗?

python-3.x - 使用 for 循环遍历字节对象 python 3x

haskell - 这个 Haskell 函数有内存功能吗?

python - Python 中的滚动哈希非常快?

python - 无法使用 python-nvd3

python - 如何从 BIO 分块句子中提取分块? - Python

haskell - Haskell 中的部分内存

haskell - 如何加速(或内存)一系列相互递归的函数