Python 使用缓存功能进行接口性能调优
背景
之前提过我们给组内开发了一个需求进度看板,数据源一周更新一次。由于数据量是两年的需求总量,接口查询比较慢,耗时10s左右。然后开发提供了一个思路,就是获取第一次请求的数据,存到缓存,后续再从缓存取数据,大大提高接口请求耗时。
python内置缓存模块
functools 模块的 lur_cache装饰器可以提供缓存功能,从而提高程序执行效率。
参数:
maxsize: 如果为None,则无限制,设置为2的幂时,性能最佳
typed: 如果typed为True,则不同参数类型的调用将分别缓存,例如f(3)和f(3.0)
示例代码:
from functools import lru_cache
# 这种缓存适合服务端
@lru_cache(maxsize=20)
def fib(n):
print("此函数执行了")
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
# 执行了函数,返回了结果 2
print(fib(3))
# 没有执行 fib函数,读取了缓存中的结果
print(fib(3))
运行结果:
释义:
使用lru_cache装饰器后,每次递归若有相同的参数调用,直接从缓存中取值,则fib(1)的调用只有一次,效率明显提升
使用redis进行缓存
上述方法可以实现本地的数据缓存,但是当我把代码发到服务器上,发现有不同集群的机器,里面的缓存不互通,不能满足我的需求,故采取redis方法设置缓存。
查了资料,使用 redis 自定义装饰器实现缓存比较适合我。下面是一个示例:
import redis
import pickle
import functools
def cache(redis_host, redis_port, redis_db, cache_time=60):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
r = redis.Redis(host=redis_host, port=redis_port, db=redis_db)
key = pickle.dumps((func.__name__, args, kwargs))
result = r.get(key)
if result:
return pickle.loads(result)
else:
result = func(*args, **kwargs)
r.setex(key, cache_time, pickle.dumps(result))
return result
return wrapper
@cache(redis_host='localhost', redis_port=6379, redis_db=0, cache_time=60)
def expensive_operation(x, y):
# some expensive operation
return result
这个装饰器函数接受4个参数:
redis_host:Redis服务器的地址
redis_port:Redis服务器的端口号
redis_db:Redis数据库的编号
cache_time:缓存的有效期时间,默认为60秒
装饰器内部定义了一个嵌套函数wrapper,这个函数负责实现缓存的逻辑。首先,使用pickle模块将函数名、参数和关键字参数打包成一个键值,然后使用Redis的get方法获取缓存中的结果,如果结果存在,则直接返回缓存结果;否则,调用被装饰的函数获取结果,再将结果保存到Redis缓存中。
装饰器会将expensive_operation的结果缓存起来,下次再调用expensive_operation函数时,如果参数相同,则直接返回缓存的结果,不用再次执行函数。这样可以大大提高程序的性能
Last updated