python中缓存模块的一些用法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010339879/article/details/82533576

python缓存模块的一些用法

一.问题描述

有时候可能需要缓存一些 成员方法的值, 可能成员方法的计算比较耗时,有时候不希望重复调用计算该值, 这个时候就可以缓存该值.

查了一下标准库 有 functools.lru_cache 有一个 lru_cache 可以缓存成员函数的值,

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@author: Frank 
@contact: [email protected]
@file: test_lru_cache.py
@time: 2018/9/8 下午8:55

"""

import time
from functools import lru_cache


class Model:

    @lru_cache(maxsize=10)
    def calculate(self, number):
        print(f'calculate({number}) is  running,', end=' ')
        print('sleep  3s  ')
        time.sleep(3)

        return number * 3


if __name__ == '__main__':

    model = Model()

    for i in range(5):
        print(model.calculate(i))

    for i in range(5):
        print(model.calculate(i))

结果如下:


calculate(0) is  running, sleep  3s  
0
calculate(1) is  running, sleep  3s  
3
calculate(2) is  running, sleep  3s  
6
calculate(3) is  running, sleep  3s  
9
calculate(4) is  running, sleep  3s  
12
0
3
6
9
12

从结果开出来, 第二次计算的时候 , 就没有计算 而是通过缓存取值, 所以成员方法只计算了一次.
lru_cache 可以指定 max_size 缓存的大小, typed bool 如果为True, 代表不同类型分别缓存. 如果达到max_size 淘汰策略是LRU, LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法.

二 第三方的模块

第三方的模块cachetools 已经提供了很多缓存策略,直接拿来用一下.
来看下面的例子.

1来看一个缓存成员方法例子
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@author: Frank 
@contact: [email protected]
@file: test_cache.py
@time: 2018/9/8 下午12:59

pip install cachetools

https://docs.python.org/3/library/operator.html

缓存成员方法的值 
cachetools  已经实现好了, 直接用就可以了. 

"""

from operator import attrgetter
import time
from cachetools import LRUCache,RRCache , cachedmethod


class Model:

    def __init__(self, cachesize):
        self.cache = LRUCache(maxsize=cachesize)

    @cachedmethod(attrgetter('cache'))
    def get_double_num(self, num):
        """ return  2* num"""
        print(f'get_double_num({num})  is running')
        time.sleep(2)
        return num * 2


model = Model(cachesize=10)

print(model.get_double_num(10))
print(model.get_double_num(10))
print(model.get_double_num(10))
print(model.get_double_num(10))
print(model.get_double_num(10))
print(model.get_double_num(10))

结果如下:

get_double_num(10)  is running
20
20
20
20
20
20

Process finished with exit code 0

可以看出, 值计算一次 函数,第二次走的是缓存. 非常好用. 在初始化方法里面构造一个缓存对象, 之后用 cachedmethod 修饰成员函数,同时 用attrgetter(‘cache’) 把cache 拿到就可以用了.

实际上 cachetools 实现了很多缓存策略,具体缓存策略可以参考下面的链接.

'Cache', 'LFUCache',
'LRUCache',
'RRCache', 'TTLCache',

‘cached’, ‘cachedmethod’ 这两个分别用来修饰 函数和成员方法的.

2 来看一个 缓存函数
# 缓存 函数的值

from cachetools import cached

@cached(cache={})
def fib(n):
    print((f'fib({n}) is  running.'))
    return n if n < 2 else fib(n - 1) + fib(n - 2)


for i in range(20):
    print('fib(%d) = %d' % (i, fib(i)))
@cached(cache={})
def fun(n):
    print(f'fun({n}) is runnnig.')
    time.sleep(3)
    return n ** 2


if __name__ == '__main__':
    for _ in range(5):
        print(fun(4))

如果cache = None , 表示不缓存,该计算结果.

结果如下:

fun(4) is runnnig.
16
16
16
16
16

直接导入 cached 里面 传入一个字典就可以了,用起来也比较方便.

实现分析:

缓存思路大致是一样的, 首先先把参数hash 一下生成一个key, 然后看key 是否在自己的缓存里,不在就计算方法(函数),之后把key和对应value 放到自己的子弟那里面. 如果下一次计算该值,生成一个key 看是否在 自己的字典里面,如果在直接返回即可. 当然这是基本的思路, 里面还有用到 缓存淘汰策略, 多线程是否要加锁,等比较复杂的问题.

三参考文档:

1.http://ningning.today/2016/01/31/python/python%E7%BC%93%E5%AD%98%E7%9A%84%E4%B8%80%E4%BA%9B%E7%94%A8%E6%B3%95/

2.gitHub地址 cachetools
https://github.com/tkem/cachetools

3.cache tools 的文档
https://cachetools.readthedocs.io/en/latest/

4.https://cachetools.readthedocs.io/en/latest/#module-cachetools.func

4.缓存算法
https://en.wikipedia.org/wiki/Cache_replacement_policies
5.缓存算法(页面置换算法)-FIFO、LFU、LRU https://www.cnblogs.com/dolphin0520/p/3749259.html


分享快乐,留住感动.2018-09-08 21:34:51 –frank

猜你喜欢

转载自blog.csdn.net/u010339879/article/details/82533576