Flask缓存技术(Flask-Cache)

为了给用户良好体验,为了节省堆统一资源多次调用所带来的资源浪费,缓存成为了Web服务器比较重要的概念。在Django中也有很多不同类别的缓存以及缓存的范围。利用内置的缓存模块,我们可以对某一页面,某一模板,某些数据进行缓存。在Flask中,也同样可以,但要使用扩展模块Flask-Cache。

基本使用方法:

app = Flask( name ) 
cache = Cache(app)

@app.route('/hello') 
@cache.cached(timeout=300, key_prefix='view_%s', unless=None) 
def hello(name=None): 
    return render_template('hello.html', name=name)

cache = Cache(app),创建缓存实例化时,cache类会自动从app配置文件中获得缓存类型,缓存时间等信息,源代码如下:

 

class Cache(object): 
  """ This class is used to control the cache objects. """
  def __init__(self, app=None, with_jinja2_ext=True, config=None):
    if not (config is None or isinstance(config, dict)):
        raise ValueError("`config` must be an instance of dict or None")

    self.with_jinja2_ext = with_jinja2_ext
    self.config = config

    self.app = app
    if app is not None:
        self.init_app(app, config)

  def init_app(self, app, config=None):
    "This is used to initialize cache with your app object"

    base_config = app.config.copy()
    if self.config:
        base_config.update(self.config)
    if config:
        base_config.update(config)
    config = base_config

    config.setdefault('CACHE_DEFAULT_TIMEOUT', 300)
    config.setdefault('CACHE_THRESHOLD', 500)
    config.setdefault('CACHE_KEY_PREFIX', 'flask_cache_')
    config.setdefault('CACHE_MEMCACHED_SERVERS', None)
    config.setdefault('CACHE_DIR', None)
    config.setdefault('CACHE_OPTIONS', None)
    config.setdefault('CACHE_ARGS', [])
    config.setdefault('CACHE_TYPE', 'null')
    config.setdefault('CACHE_NO_NULL_WARNING', False)


    if self.with_jinja2_ext:
        from .jinja2ext import CacheExtension, JINJA_CACHE_ATTR_NAME

        setattr(app.jinja_env, JINJA_CACHE_ATTR_NAME, self)
        app.jinja_env.add_extension(CacheExtension)

    self._set_cache(app, config)

从上面代码中就可以看出,init_app方法浅拷贝了app的config对象。配置之后会设定cache对象。cache对象默认为simple,使用本地Python字典缓存。这不是真正的线程安全。,此外还有RedisCache,SASLMemcachedCache等等。

这里最关键的是缓存的cached方法,该方法是一个装饰器,经过该装饰器修饰的视图函数,会自动将视图函数返回值存储到指定的缓存值,存储形式是key-value.

cached方法原型:


def cached(self, timeout=None, key_prefix='view/%s', unless=None):
    """
    Decorator. Use this to cache a function. By default the cache key
    is `view/request.path`. You are able to use this decorator with any
    function by changing the `key_prefix`. If the token `%s` is located
    within the `key_prefix` then it will replace that with `request.path`

    :param timeout: Default None. If set to an integer, will cache for that
                    amount of time. Unit of time is in seconds.
    :param key_prefix: Default 'view/%(request.path)s'. Beginning key to .
                       use for the cache key.

    :param unless: Default None. Cache will *always* execute the caching
                   facilities unless this callable is true.
                   This will bypass the caching entirely.
    """

    def decorator(f):
        @functools.wraps(f)
        def decorated_function(*args, **kwargs):

            try:
                cache_key = decorated_function.make_cache_key(*args, **kwargs)

                rv = self.cache.get(cache_key)
            except Exception:
                if current_app.debug:
                    raise
                logger.exception("Exception possibly due to cache backend.")
                return f(*args, **kwargs)

            if rv is None:
                rv = f(*args, **kwargs)
                try:
                    self.cache.set(cache_key, rv,
                               timeout=decorated_function.cache_timeout)
                except Exception:
                    if current_app.debug:
                        raise
                    logger.exception("Exception possibly due to cache backend.")
                    return f(*args, **kwargs)
            return rv

        def make_cache_key(*args, **kwargs):
            if callable(key_prefix):
                cache_key = key_prefix()
            elif '%s' in key_prefix:
                cache_key = key_prefix % request.path
            else:
                cache_key = key_prefix

            return cache_key

        decorated_function.uncached = f
        decorated_function.cache_timeout = timeout
        decorated_function.make_cache_key = make_cache_key

        return decorated_function
    return decorator

上述代码还是比较好理解,首先根据cache_key(默认是request.path,即当前路由)取值,如果存在,即直接返回value值,如果没有,那么就执行该函数,并把函数返回值存到缓存中。

上面是一个三层装饰器,一般装饰器本身需要带参数的都采用三层。

 

我真是觉得上面的缓存装饰器写得特别好,我后来在Django项目中就根据这个写了一个缓存装饰器。

 

 

--------EOF---------
微信分享/微信扫码阅读