├── .gitignore ├── README.md ├── autocache.py ├── autocache_redis.py ├── cache.py ├── test_autocache.py ├── test_autocache_redis.py └── test_cache.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python装饰器自动缓存系统(autocache.py) 2 | 3 | ### 说明 4 | 5 | - 这是一个函数装饰器,用来给函数增加缓存。 6 | - 程序根据函数名和参数自动缓存,可以设置缓存时间(秒)。 7 | - 只要函数名和参数完全相同并且缓存时间没到,则直接返回缓存里面的值。否则执行函数,再将结果缓存。 8 | 9 | ### 使用方法 10 | 11 | 参考 [test_autocache.py](test_autocache.py) 12 | 13 | ### 优点 14 | 15 | - 使用简单方便,直接在要缓存的函数前加装饰器即可 16 | - 根据函数名和参数进行缓存,更加智能 17 | 18 | ### 存在问题 19 | 20 | - 函数的缓存时间只能在函数定义的时候设置一次 21 | - 缓存存在内存里,只能在程序结束时释放 22 | 23 | # python装饰器自动缓存系统(redis持久化)(autocache_redis.py) 24 | 25 | 和上面的装饰器自动缓存功能相同,增加redis,可以将数据持久化。 26 | 27 | # python键值缓存系统(cache.py) 28 | 29 | ### 说明 30 | 31 | - 经典的键值缓存系统,类似于memcached, 32 | - 通过set方法来将内容缓存起来, 可以设置生存时间。 33 | - 通过get方法从缓存中获取数据,当然只有在生存时间内的内容才能被返回,超过了生存时间,直接返回None。 34 | - 通过delete方法删除缓存, 35 | - 通过clear方法清空缓存。 36 | 37 | ### 经典用法: 38 | 39 | 假设有一条`python`语句的执行时间很长,结果在一段时间内不会变化,我们可以对这条语句进行缓存。 40 | 41 | 例如:有一个sql查询要花费较长时间 42 | 43 | `result = sql()` 44 | 45 | 然后我们可以用我的小缓存系统进行缓存处理,可以用下面的语句来替代 46 | 47 | ```python 48 | cache = Cache() 49 | result = cache.get("sql_result") 50 | if result is None: 51 | result = sql() 52 | cache.set(key='sql_result', data=result, age=10) 53 | ``` 54 | 55 | 解释一下:首先从缓存中读取元素,如果在缓存中,直接从缓存中获得,如果缓存中没有,则执行sql查询并将结果存入缓存,并设置生存时间为10秒 56 | 57 | ### 其他用法 58 | 59 | 参考 [test_cache.py](test_cache.py) 60 | 61 | ### 优点 62 | 63 | - 直接对函数的返回值进行缓存,不依赖于具体函数 64 | - 方法操作比较全面,能对具体的键值对进行操作 65 | 66 | ### 存在问题 67 | 68 | - 用户自定义`key`,如果key相同则会覆盖原来的值 69 | - 没有持久化,程序结束缓存删除 70 | 71 | -------------------------------------------------------------------------------- /autocache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding=utf-8 3 | 4 | '''装饰器版的python自动缓存系统''' 5 | 6 | import time 7 | import hashlib 8 | import pickle 9 | from functools import wraps 10 | 11 | _cache = {} 12 | 13 | def _is_obsolete(entry, duration): 14 | '''是否过期''' 15 | if duration == -1: #永不过期 16 | return False 17 | return time.time() - entry['time'] > duration 18 | 19 | def _compute_key(function, args,kw): 20 | '''序列化并求其哈希值''' 21 | key = pickle.dumps((function.func_name,args,kw)) 22 | return hashlib.sha1(key).hexdigest() 23 | 24 | def memorize(duration = -1): 25 | '''自动缓存''' 26 | def _memoize(function): 27 | @wraps(function) # 自动复制函数信息 28 | def __memoize(*args, **kw): 29 | key = _compute_key(function, args, kw) 30 | #是否已缓存? 31 | if key in _cache: 32 | #是否过期? 33 | if _is_obsolete(_cache[key], duration) is False: 34 | return _cache[key]['value'] 35 | # 运行函数 36 | result = function(*args, **kw) 37 | #保存结果 38 | _cache[key] = { 39 | 'value' : result, 40 | 'time' : time.time() 41 | } 42 | return result 43 | return __memoize 44 | return _memoize 45 | -------------------------------------------------------------------------------- /autocache_redis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding=utf-8 3 | 4 | '''装饰器版的python自动缓存系统,使用redis持久化数据库''' 5 | 6 | import hashlib 7 | import pickle 8 | import redis 9 | from functools import wraps 10 | 11 | r = redis.Redis(host="localhost",port=6379,db=0) 12 | 13 | def _compute_key(function, args,kw): 14 | '''序列化并求其哈希值''' 15 | key = pickle.dumps((function.func_name,args,kw)) 16 | return hashlib.sha1(key).hexdigest() 17 | 18 | def memorize(duration = -1): 19 | '''自动缓存''' 20 | def _memoize(function): 21 | @wraps(function) # 自动复制函数信息 22 | def __memoize(*args, **kw): 23 | key = _compute_key(function, args, kw) 24 | #是否已缓存? 25 | if r.exists(key): 26 | try: # 判断存在和返回之间还有一段时间,可能造成key不存在 27 | return r[key] 28 | except: 29 | pass 30 | # 运行函数 31 | result = function(*args, **kw) 32 | #保存结果 33 | r[key] = result 34 | r.expire(key,duration) 35 | return result 36 | return __memoize 37 | return _memoize 38 | -------------------------------------------------------------------------------- /cache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding=utf-8 3 | from time import time 4 | class Cache: 5 | '''简单的缓存系统''' 6 | def __init__(self): 7 | '''初始化''' 8 | self.mem = {} 9 | self.time = {} 10 | 11 | def set(self, key, data, age=-1): 12 | '''保存键为key的值,时间位age''' 13 | self.mem[key] = data 14 | if age == -1: 15 | self.time[key] = -1 16 | else: 17 | self.time[key] = time() + age 18 | return True 19 | 20 | def get(self,key): 21 | '''获取键key对应的值''' 22 | if key in self.mem.keys(): 23 | if self.time[key] == -1 or self.time[key] > time(): 24 | return self.mem[key] 25 | else: 26 | self.delete(key) 27 | return None 28 | else: 29 | return None 30 | 31 | def delete(self,key): 32 | '''删除键为key的条目''' 33 | del self.mem[key] 34 | del self.time[key] 35 | return True 36 | 37 | def clear(self): 38 | '''清空所有缓存''' 39 | self.mem.clear() 40 | self.time.clear() 41 | -------------------------------------------------------------------------------- /test_autocache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding=utf-8 3 | from autocache import memorize 4 | 5 | @memorize(3) 6 | def a_hard_function(a): 7 | '''一个需要缓存的函数''' 8 | print "getting result" 9 | from time import sleep 10 | import random 11 | sleep(2) 12 | return a,random.randint(1,100) 13 | 14 | if __name__=='__main__': 15 | while True: 16 | print a_hard_function(1) 17 | print a_hard_function(2) 18 | print a_hard_function.__doc__ #函数文档保持不变 19 | -------------------------------------------------------------------------------- /test_autocache_redis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding=utf-8 3 | from autocache_redis import memorize 4 | 5 | @memorize(3) 6 | def a_hard_function(a): 7 | '''一个需要缓存的函数''' 8 | print "getting result" 9 | from time import sleep 10 | import random 11 | sleep(2) 12 | return a,random.randint(1,100) 13 | 14 | if __name__=='__main__': 15 | while True: 16 | print a_hard_function(1) 17 | print a_hard_function(2) 18 | print a_hard_function.__doc__ #函数文档保持不变 19 | -------------------------------------------------------------------------------- /test_cache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding=utf-8 3 | from cache import Cache 4 | 5 | def a_hard_function(): 6 | '''一个需要缓存的函数''' 7 | print "getting result" 8 | from time import sleep 9 | import random 10 | sleep(2) 11 | print "done" 12 | return random.randint(1,100) 13 | 14 | if __name__ == "__main__": 15 | cache = Cache() 16 | cache.set('a','aaaa',5) #a的值是'aaaa',生存时间位5秒 17 | cache.set('b',[1,2]) #b的值是[1,2],生存时间无限长 18 | while True: 19 | result = cache.get("hard_func") 20 | if result is None: 21 | result = a_hard_function() 22 | cache.set("hard_func",result,2) 23 | print cache.get('a'), 24 | print cache.get('b'), 25 | print result 26 | --------------------------------------------------------------------------------