今天在看《 python高级编程》 python缓存这一小节。在这里记录下学习笔记。
什么是缓存大家都明白,就是对某一个复杂的计算进行缓存,等待下一次请求的时候可以避免再次计算而直接返回结果。这样可以改善程序的性能 。
一、最基础的缓存
看《python高级编程》 中的程序例子:
#!/usr/bin/python # -*- coding:utf8 -*- import time import hashlib import pickle from itertools import chain cache = {} def is_obsolete(cache_entry,duration): ''' 检查cache有没有过期 ''' return time.time() - cache_entry['time'] > duration def compute_key(function,args,kw): ''' 对函数进行 hash 取得唯一值''' key = pickle.dumps((function.func_name,args,kw)) return hashlib.sha1(key).hexdigest() def memoize(duration=10): def _memoize(function): def __memoize(*args,**kw): key = compute_key(function,args,kw) if ( key in cache and not is_obsolete(cache[key],duration)): print 'we got a winner' return cache[key]['value'] result = function(*args,**kw) cache[key] = {'value':result, 'time':time.time()} return result return __memoize return _memoize @memoize(10) #10秒之后缓存会失效 def very_very_complex_stuff(a,b): print a+b very_very_complex_stuff(100,200)
以上的代码,可以称之为 缓存装饰器 , 使用起来也是较为方便 。
二、实际如何应用
一个技术 有没有价值,最看它可以运用在什么地方 。千言万语,还不如我们一起来看下Django 的源码吧,看django是如何使用缓存的.
有使用Django的朋友,可以参考文章:Django缓存机制 http://py3k.cn/chapter13/
其中有一个View层的缓存,代码示例如下:
from django.views.decorators.cache import cache_page @cache_page(60 * 15) def my_view(request, param): # ...看到这里,大概明白了 缓存装饰器 可以应用在哪些地方 。接下来我们看下Django 的实现方法 :
Django的 FetchFromCacheMiddleware 中间件会处理这个请求:
class FetchFromCacheMiddleware(object): def __init__(self): ……………………………… def process_request(self, request): """ Checks whether the page is already cached and returns the cached version if available. """ if not request.method in ('GET', 'HEAD'): request._cache_update_cache = False return None # Don't bother checking the cache.
由于django 封装了 基于内存的缓存、基于文件的缓存 、基于memcache的缓存等接口。 这里主要看基于文件的缓存 。
ubuntu@yee:/usr/local/lib/python2.7/dist-packages/django/core/cache/backends$ vim filebased.py
def set(self, key, value, timeout=None, version=None)://value 是一个response对象 key = self.make_key(key, version=version) #创建key self.validate_key(key) #验证key 是否已经存在 fname = self._key_to_file(key) dirname = os.path.dirname(fname) if timeout is None: timeout = self.default_timeout self._cull() try: if not os.path.exists(dirname): os.makedirs(dirname) f = open(fname, 'wb') try: now = time.time() pickle.dump(now + timeout, f, pickle.HIGHEST_PROTOCOL) pickle.dump(value, f, pickle.HIGHEST_PROTOCOL) #将value 写入 文件中缓存起来 finally: f.close() except (IOError, OSError): pass
Django的方法是,将response对象 pickle 之后保存在文件中。跟<python高级编程>中的方法是一样的。
获取缓存 :
def get(self, key, default=None, version=None): key = self.make_key(key, version=version) self.validate_key(key) fname = self._key_to_file(key) try: f = open(fname, 'rb') try: exp = pickle.load(f) now = time.time() if exp < now: self._delete(fname) else: return pickle.load(f) finally: f.close() except (IOError, OSError, EOFError, pickle.PickleError): pass return default
通过django 可以看出python的缓存是如何实现的了。如果想更深入的了解,还需要更多的去研究源码。
笔记就记到这里。Over。