首页 论坛 置顶 Python中的缓存!

正在查看 1 个帖子:1-1 (共 1 个帖子)
  • 作者
    帖子
  • #14812

    探索 Python 的 functools: 缓存、缓存属性和 LRU 缓存

    Python 的 functools 模块是功能编程爱好者的宝藏,提供了使代码更高效和优雅的工具。在这篇文章中,我们将深入探讨三个强大的函数——cachecached_propertylru_cache——它们通过存储昂贵计算的结果来帮助优化性能。无论是加速递归算法还是简化基于类的计算,这些工具都能满足你的需求。让我们通过清晰的解释和实际的例子来探索每一个工具。

    1. cache: 简单的无界备忘录

    cache 装饰器是一种轻量级的方式来备忘函数结果,当相同的输入再次出现时存储它们以供重用。它就像是你函数输出的便签——无需重新计算!

    工作原理
    • 功能:在一个无限制的字典中存储函数结果,使用参数作为键。
    • 使用时机:适用于计算开销大的纯函数(相同输入,相同输出)。
    • 主要特点:它等同于 lru_cache(maxsize=None),但由于其简单性而更快。

    示例

    from functools import cache
    
    @cache
    def factorial(n):
        return n * factorial(n-1) if n else 1
    
    print(factorial(10))  # 计算结果:3628800
    
    print(factorial(10))  # 返回缓存结果,无需重新计算
    
    为什么它很棒
    • 速度:避免冗余计算,使得像阶乘这样的递归函数速度极快。
    • 简单性:无需配置——只需添加装饰器即可。
    • 警告:缓存会无限增长,因此对于具有许多唯一输入的函数,请监控内存使用情况。

     

    2. cached_property: 一次性属性计算

    cached_property 装饰器将类方法转换为一个属性,该属性只计算一次其值并为实例缓存该值。可以将其视为一个懒加载的属性,它会一直存在。

    工作原理
    • 它的作用:第一次访问时运行该方法,将结果缓存为实例属性,并在后续调用中返回缓存的值。
    • 何时使用:非常适合在第一次计算后不会改变的类中的昂贵计算。
      关键特性:仅适用于实例方法(需要 self)。

    示例

    from functools import cached_property
    
    class Circle:
        def __init__(self, radius):
            self.radius = radius
    
        @cached_property
    
        def area(self):
            print("计算面积")
            return 3.14159 * self.radius ** 2
    
    c = Circle(5)
    print(c.area)  # 输出: 计算面积,然后 78.53975
    print(c.area)  # 输出: 78.53975(缓存,无需重新计算)

    为什么它很棒
    • 效率:每个实例仅计算一次,节省CPU周期。
    • 简洁代码:像属性一样读取(c.area vs. c.area()),无缝融入类设计。
    • 注意事项:缓存的值可以被覆盖(例如,c.area = 0),因此应将其用于不可变数据。

     

    3. lru_cache:灵活的、有界的记忆化

    lru_cache装饰器是记忆化的强力工具,提供可配置大小的最近最少使用(LRU)缓存。它是线程安全的,并且具有丰富的反射特性,使其成为优化复杂函数的首选。

     

    它是如何工作的
    • 它的功能:缓存最多maxsize个结果,当缓存满时驱逐最近最少使用的条目。支持类型选项,将不同类型(例如,3与3.0)视为不同的键。
    • 何时使用:非常适合递归算法、动态规划或任何具有重复调用的函数。
    • 关键特性:提供 cache_info() 方法以检查命中、未命中和缓存大小。

     

    示例

    from functools import lru_cache
    
    @lru_cache(maxsize=32)
    def fib(n):
        if n < 2:
            return n
        return fib(n-1) + fib(n-2)
    
    print(fib(10))  # 计算结果:55
    
    print(fib.cache_info())  # 显示: CacheInfo(hits=8, misses=11, maxsize=32, currsize=11)

     

    为什么它很棒
    • 控制:设置最大大小以平衡内存和性能(使用 None 表示无限制,如缓存)。
    • 线程安全:适用于多线程应用程序,确保缓存保持一致性。
    • 调试:cache_info() 帮助您通过揭示缓存的有效性来调整性能。
    • 注意:避免与具有副作用的函数一起使用,因为缓存假设输出是确定性的。
正在查看 1 个帖子:1-1 (共 1 个帖子)
  • 哎呀,回复话题必需登录。