详解Python 记忆化和缓存

  • Post category:Python

Python的记忆化和缓存技术可以提高程序的效率,特别是对于一些计算量大、耗时多的函数,使用记忆化和缓存技术可以节省程序的执行时间,提高程序的运行效率。

什么是记忆化

记忆化就是将每次函数调用结果缓存起来,以备后续使用,避免重复计算。通俗来说,可以把记忆化视为一种加速工具,使得程序不必每次都重新计算每个函数,相当于把结果保存在内存中,后续使用时直接读取内存中的结果即可。

Python中的functools模块提供了lru_cache装饰器,实现记忆化功能。

如何使用记忆化

可以通过Python内置的functools模块里的lru_cache装饰器实现记忆化技术。

from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

在上面的代码中,我们定义了一个名为fibonacci的函数,用于计算斐波那契数列的第n项。我们使用@lru_cache(maxsize=None)来装饰该函数,表示将该函数加入缓存机制。缓存的大小默认为无限大,可以自行设置缓存大小;

什么是缓存

缓存是一种将数据存储在内存中的技术,以便在将来的某个时间或与将来相关的事物中,可以快速地检索数据。缓存的目的是为了加速数据的读取和处理过程,从而提高程序的执行效率。缓存技术通常用于一些需要频繁读取的数据,例如网络请求、磁盘读写等。

Python中的functools模块还提供了一个叫做cache的函数来实现缓存的功能。

如何使用缓存

from functools import cache

@cache
def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n-1)

在上面的代码中,我们定义了一个名为factorial的函数,用于计算n的阶乘。我们使用@cache来装饰该函数,表示将该函数加入缓存机制。

需要注意的是,使用cache装饰器时,函数的参数必须是可哈希的,不支持任意类型的参数。

示例说明

from timeit import timeit
from functools import lru_cache

# 使用递归实现斐波那契数列
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# 使用lru_cache装饰器来实现记忆化,提高效率
@lru_cache(maxsize=None)
def fibonacci_cache(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)


t1 = timeit(lambda: fibonacci(30), number=10000)
t2 = timeit(lambda: fibonacci_cache(30), number=10000)

print(f"Without cache: {t1:.5f}")
print(f"With cache: {t2:.5f}")

在这个示例程序中,我们使用递归实现斐波那契数列。首先我们分别测试未使用缓存(即使用递归实现斐波那契数列)和使用lru_cache装饰器来实现记忆化(即使用斐波那契数列的缓存机制)的情况下计算斐波那契数列第30个数字的时差。程序运行10,000次,然后计算其平均耗时。

输出结果为:
Without cache: 19.59625 seconds
With cache: 0.02073 seconds

在使用缓存机制的情况下,程序的执行效率提高了约945倍,非常显著。

from functools import cache

# 计算数组的的乘积
def prod(numbers):
    if len(numbers) == 1:
        return numbers[0]
    else:
        return numbers[0] * prod(numbers[1:])

# 使用cache装饰器来实现缓存,提高效率
@cache
def prod_cache(numbers):
    if len(numbers) == 1:
        return numbers[0]
    else:
        return numbers[0] * prod_cache(numbers[1:])

numbers = [1,2,3,4,5,6,7,8,9,10]

print(prod(numbers))
print(prod_cache(tuple(numbers)))

在上面的代码中,我们定义了一个名为prod的函数,用于计算数组的乘积。我们使用cache来装饰该函数,表示将该函数加入缓存机制。

我们定义了一个长度为10的列表,并在两个函数中同时计算并输出了该列表的乘积。在prod_cache函数中,由于我们已经使用了缓存机制,所以在后续计算中,程序直接返回了缓存的结果,而不用再次计算。