网站首页 > 技术文章 正文
对话实录
小白:(苦恼)我写的一些函数计算特别耗时,每次调用都要重新计算,太浪费时间了,有没有办法优化呀?
专家:(神秘一笑)那你一定要了解lru_cache这个神奇的功能!它能像一个智能小助手,帮你的函数提升性能,接下来我给你好好讲讲。
lru_cache基础认识
1. 什么是lru_cache
lru_cache(Least Recently Used cache,最少使用缓存)是functools模块中的一个装饰器。简单来说,它会记住函数之前的计算结果。当函数再次被调用时,如果传入的参数和之前某次调用一样,它就直接返回之前缓存的结果,而不用重新计算,大大节省了时间。
2. 如何使用lru_cache
只需在函数定义前加上@lru_cache装饰器即可。例如,有一个计算阶乘的函数:
from functools import lru_cache
@lru_cache(maxsize = 128)
def factorial(n):
if n == 0 or n == 1:
return 1
return n * factorial(n - 1)
这里maxsize = 128表示缓存最多可以存储 128 个不同参数对应的结果。当缓存满了,它会把最近最少使用的结果清除掉,为新的结果腾出空间。
lru_cache常用场景
案例 1:递归函数-计算斐波那契数列
斐波那契数列由意大利数学家莱昂纳多斐波那契(Leonardo Fibonacci)在1202 年提出。它的定义是从第三项开始,每一项都等于前两项之和,即F(n)=F(n-1)+F(n-2)(n≥3,F(1)=1,F(2)=1
斐波那契数列的计算非常适合展示lru_cache的强大之处。因为在计算过程中,会有大量重复的子问题计算。
from functools import lru_cache
@lru_cache(maxsize = 128)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 计算第30个斐波那契数
print(fibonacci(30))
接下里我们使用之前介绍的执行时间的模块timeit来对比使用lru_cache和不使用lru_cache时的执行时长。为了方便查看结果,并且保证计算结果的准确性,我们打印了结果值,供大家参考。
import timeit
#1 不使用lru_cache 计算n=20的执行时长 打印执行结果 方便我们确认每次执行结果是一致的
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
total_time = timeit.timeit(stmt='global result;result = fibonacci(20);print(f"运行结果:{result}")',setup='from __main__ import fibonacci',number=1000)
print(f"运行总耗时:{total_time:.6f}秒") #->1000次运行平均耗时
#2 使用lru_cache 计算n=20的执行时长
@lru_cache(maxsize = 128)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
total_time = timeit.timeit(stmt='global result;result =fibonacci(20);print(f"运行结果:{result}")',setup='from __main__ import fibonacci',number=1000)
print(f"运行总耗时:{total_time:.6f}秒") #->1000次运行平均耗时
程序执行后 ,结果如下:
运行总耗时:1.662857秒
运行总耗时:0.001898秒
#可以看出使用lru_cache后,效率提升了930倍。
案例 2:复杂数学计算
假设有一个数学函数,比如计算一个多项式的值:
from functools import lru_cache
@lru_cache(maxsize = 128)
def complex_math(x):
result = 3 * x ** 4
return result
for i in range(10):
value = complex_math(i)
print(f"x = {i}, result = {value}")
在实际应用中,一些复杂的数学计算可能会耗费大量资源。通过lru_cache,当重复计算时,直接返回缓存结果,提高了程序运行效率。
案例 3:文件读取与处理
有时候我们需要从文件中读取数据并进行处理,而文件读取操作相对耗时。如果每次读取相同文件并处理的结果可以复用,就可以使用lru_cache。
from functools import lru_cache
@lru_cache(maxsize = 10)
def read_and_process_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
data = file.read()
word_count = len(data.split())
return word_count
闭坑指南
缓存占用内存问题
lru_cache的缓存会占用内存空间。如果maxsize设置得过大,可能导致程序占用过多内存,影响系统性能。例如:
from functools import lru_cache
# 错误示范,maxsize设置过大
@lru_cache(maxsize = 10000)
def some_function(x):
return x * x
# 假设这里频繁调用函数,会占用大量内存
for i in range(10000):
some_function(i)
在设置maxsize时,要根据实际情况和系统内存状况合理调整,确保在提升性能的同时,不会对内存造成过大压力。
缓存失效问题
当被缓存函数的计算逻辑发生改变,或者函数依赖的外部资源(如文件内容)发生变化时,缓存可能不会自动更新,导致返回的是旧结果。例如:
from functools import lru_cache
@lru_cache(maxsize = 128)
def calculate_value(x):
# 假设这里的计算逻辑改变了,但缓存未更新
return x * 2
# 第一次调用,结果被缓存
result1 = calculate_value(5)
# 函数逻辑改变后,未清除缓存
# 第二次调用仍返回缓存的旧结果
result2 = calculate_value(5)
在修改函数逻辑或外部资源变化后,需要手动清除缓存。可以使用cache_clear方法,例如
calculate_value.cache_clear(),或者重新启动程序,以确保获取到最新的计算结果。
专家工具箱
1. 缓存命中率分析
通过cache_info方法可以获取lru_cache的缓存信息,包括命中次数、未命中次数等。这有助于分析缓存的使用情况,进而优化缓存设置。例如:
from functools import lru_cache
@lru_cache(maxsize = 128)
def complex_calculation(x):
# 模拟复杂计算
return x * x * x
# 多次调用函数
for i in range(10):
complex_calculation(i)
for i in range(10):
complex_calculation(i)
for i in range(10):
complex_calculation(i)
cache_info = complex_calculation.cache_info()
print(cache_info)
#输出结果:
CacheInfo(hits=20, misses=10, maxsize=128, currsize=10)
#第1次执行for循环时 并没有命中,等第2次和第3次执行时都命中了
输出的cache_info包含hits(命中次数)、misses(未命中次数)、maxsize(最大缓存数量)和currsize(当前缓存数量)等信息。
2. 缓存类型设置
lru_cache还有一个typed参数,默认为False。当typed = True时,不同类型但值相同的参数会被视为不同的缓存键。例如:
from functools import lru_cache
#设置 typed = True的场景
@lru_cache(maxsize = 128, typed = True)
def add_numbers(a, b):
return a + b
result1 = add_numbers(2, 3)
result2 = add_numbers(2.0, 3.0)
cache_info = add_numbers.cache_info()
print(cache_info)
# 不设置typed,默认为False
@lru_cache(maxsize = 128)
def add_numbers(a, b):
return a + b
result1 = add_numbers(2, 3)
result2 = add_numbers(2.0, 3.0)
cache_info = add_numbers.cache_info()
print(cache_info)
#输出结果:
CacheInfo(hits=0, misses=2, maxsize=128, currsize=2)
CacheInfo(hits=1, misses=1, maxsize=128, currsize=1)
在这个例子中,当typed默认为 False时,add_numbers(2, 3)和add_numbers(2.0, 3.0)会被视为相同的调用,因为2和2.0在数值上相等,所以显示命中了1次。但当typed = True时,它们会被当作不同的调用,分别缓存结果,显示并没有命中。
小白:(恍然大悟)哇,lru_cache原来这么厉害,能解决我这么多函数性能问题!
专家:(点头)没错,掌握好lru_cache的使用,能让你的Python程序运行得更加高效,快去实践一下吧!
lru_cache常用设置及方法速查表
设置 / 方法 | 用法 | 说明 |
maxsize | @lru_cache(maxsize = 128) | 设置缓存的最大数量,当缓存满时,删除最近最少使用的缓存项 |
typed | @lru_cache(maxsize = 128, typed = False) | 控制是否区分不同类型但值相同的参数,默认为False |
cache_clear | function.cache_clear() | 手动清除缓存 |
cache_info | function.cache_info() | 获取缓存信息,包括命中次数、未命中次数等 |
猜你喜欢
- 2025-06-10 【Python】性能加速之解析器加速Pypy 库使用说明
- 2025-06-10 【Python】性能加速之解析器加速Brython 库使用说明
- 2025-06-10 Rust与Python的文件系统性能对比分析:你可能想知道的一切
- 2025-06-10 比C语言还快20%!Mojo首个大模型开放下载,性能达Python版250倍
- 2025-06-10 Java、Go 和 Python 多线程性能对比
- 2025-06-10 Python编程通过懒属性提升性能(python性能调优)
- 2025-06-10 Python 3.13.0 重磅发布:性能起飞,GIL 不再是瓶颈!
- 2025-06-10 精通Python多进程(Multiprocessing)提升性能:8 个进阶层次解析
- 2025-06-10 Python 3.13 启动自由线程,性能会下降吗?
- 2025-06-10 Python3.11性能测评超3.10近64%
- 06-12python读取excel文件 xlrd模块(如何用python读取excel)
- 06-12怎么在Python中操作Excel文件?(python2.7操作excel)
- 06-12Excel变天!微软把Python「塞」进去了,直接可搞机器学习
- 06-12Python自动化-Excel:pandas新建、读取excel文件
- 06-12Python之Pandas使用系列(八):读写Excel文件的各种技巧
- 06-12十分钟教会你使用Python操作excel,内附步骤和代码
- 06-12Python读取与写入Excel模块:openpyxl
- 06-12Python玩转Excel,使用Python读取Excel文件如此简单!
- 265℃Python短文,Python中的嵌套条件语句(六)
- 264℃python笔记:for循环嵌套。end=""的作用,图形打印
- 263℃PythonNet:实现Python与.Net代码相互调用!
- 259℃Python实现字符串小写转大写并写入文件
- 257℃Python操作Sqlserver数据库(多库同时异步执行:增删改查)
- 117℃原来2025是完美的平方年,一起探索六种平方的算吧
- 98℃Python 和 JavaScript 终于联姻了!PythonMonkey 要火?
- 90℃Ollama v0.4.5-v0.4.7 更新集合:Ollama Python 库改进、新模型支持
- 最近发表
-
- python读取excel文件 xlrd模块(如何用python读取excel)
- 怎么在Python中操作Excel文件?(python2.7操作excel)
- Excel变天!微软把Python「塞」进去了,直接可搞机器学习
- Python自动化-Excel:pandas新建、读取excel文件
- Python之Pandas使用系列(八):读写Excel文件的各种技巧
- 十分钟教会你使用Python操作excel,内附步骤和代码
- Python读取与写入Excel模块:openpyxl
- Python玩转Excel,使用Python读取Excel文件如此简单!
- Python之使用xlrd库读取Excel数据
- Python自动化:openpyxl读取excel(openpyxl读写excel)
- 标签列表
-
- python中类 (31)
- python 迭代 (34)
- python 小写 (35)
- python怎么输出 (33)
- python 日志 (35)
- python语音 (31)
- python 工程师 (34)
- python3 安装 (31)
- python音乐 (31)
- 安卓 python (32)
- python 小游戏 (32)
- python 安卓 (31)
- python聚类 (34)
- python向量 (31)
- python大全 (31)
- python次方 (33)
- python桌面 (32)
- python总结 (34)
- python浏览器 (32)
- python 请求 (32)
- python 前端 (32)
- python验证码 (33)
- python 题目 (32)
- python 文件写 (33)
- python中的用法 (32)