1. 程式人生 > >python中快取模組的一些用法

python中快取模組的一些用法

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 看是否在 自己的字典裡面,如果在直接返回即可. 當然這是基本的思路, 裡面還有用到 快取淘汰策略, 多執行緒是否要加鎖,等比較複雜的問題.

三參考文件:

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