什么是缓存大家都明白,就是对某一个复杂的计算进行缓存,等待下一次请求的时候可以避免再次计算而直接返回结果。这样可以改善程序的性能 。
一、最基础的缓存
看《python高级编程》 中的程序例子:
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的缓存等接口。 这里主要看基于文件的缓存 。
写缓存:
/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的缓存是如何实现的了。如果想更深入的了解,还需要更多的去研究源码。