Flask 擴展 緩存


如果同一個請求會被多次調用,每次調用都會消耗很多資源,並且每次返回的內容都相同,就該使用緩存了

自定義緩存裝飾器

在使用Flask-Cache擴展實現緩存功能之前,我們先來自己寫個視圖緩存裝飾器,方便我們來理解視圖緩存的實現。首先,我們要有一個緩存,Werkzeug框架中的提供了一個簡單的緩存對象SimpleCache,它是將緩存項存放在Python解釋器的內存中,我們可以用下面的代碼獲取SimpleCache的緩存對象:

from werkzeug.contrib.cache import SimpleCache
cache = SimpleCache()

如果你要使用第三方的緩存服務器,比如Memcached,Werkzeug框架也提供了它的wrapper:

from werkzeug.contrib.cache import MemcachedCache
cache = MemcachedCache(['127.0.0.1:11211'])

此后就可以使用cache對象的”set(key, value, timeout)”和”get(key)”方法來存取緩存項了。注意”set()”方法的第三個參數”timeout”是緩存過期時間,默認為0,也就是永不過期。

def cached(timeout=5 * 60, key='view_%s'):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            cache_key = key % request.path
            value = cache.get(cache_key)
            if value is None:
                value = f(*args, **kwargs)
                cache.set(cache_key, value, timeout=timeout)
            return value
        return decorated_function
    return decorator

裝飾器的兩個參數分別是緩存的過期時間,默認是5分鍾;緩存項鍵值的前綴,默認是”view_”。然后我們寫個視圖,並使用此裝飾器:

@app.route('/hello')
@app.route('/hello/<name>')
@cached()
def hello(name=None):
    print 'view hello called'
    return render_template('hello.html', name=name)

我們試下訪問這個視圖,對於同樣的URL地址,第一次訪問時,控制台上會有”view called”輸出,第二次就不會了。如果過5分鍾后訪問,”view called”才會再次輸出。

安裝和啟用Flask-Cache

了解了緩存裝飾器的內部實現,我們就可以開始介紹Flask的緩存擴展,Flask-Cache。首先使用pip將其安裝上:

pip install flask-cache

然后創建一個Flask-Cache的實例:

from flask import Flask
from flask_cache import Cache
 
app = Flask(__name__)
cache = Cache(app, config={'CACHE_TYPE': 'simple'})

上例中,我們使用了’simple’類型緩存,其內部實現就是Werkzeug中的SimpleCache。我們也可以使用第三方的緩存服務器,比如Redis,代碼如下:

cache = Cache(app, config={'CACHE_TYPE': 'redis',          # Use Redis
                           'CACHE_REDIS_HOST': 'abc.com',  # Host, default 'localhost'
                           'CACHE_REDIS_PORT': 6379,       # Port, default 6379
                           'CACHE_REDIS_PASSWORD': '111',  # Password
                           'CACHE_REDIS_DB': 2}            # DB, default 0

其內部實現是”werkzeug.contrib.cache”包下的”RedisCache”,所以說Flask-Cache就是基於Werkzeug框架的Cache庫實現的。

應用中使用緩存

同自定義緩存裝飾器一樣,我們可以用cache對象的”cached()”方法來裝飾視圖函數,以達到緩存視圖的目的:

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

“cache.cached()”裝飾器有三個參數:

  • timeout:過期時間,默認為None,即永不過期
  • key_prefix:緩存項鍵值的前綴,默認為”view/%s”
  • unless:回調函數,當其返回True時,緩存不起作用。默認為None,即緩存有效

除了裝飾視圖函數,”cache.cached()”裝飾器也可以用來裝飾普通函數:

@cache.cached(timeout=50, key_prefix='get_list')
def get_list():
    print 'method get_list called'
    return ['a','b','c','d','e']
 
@app.route('/list')
def list():
    return ', '. join(get_list())

我們訪問”/list”地址時,第一次控制台上會有”method called”輸出,第二次就不會了,說明緩存起效了。裝飾普通函數時必須指定明確的”key_prefix”參數,因為它不像視圖函數,可以使用請求路徑”request.path”作為緩存項的鍵值。如果函數帶參數,對於不同的參數調用,都會使用同一緩存項,即返回結果一樣。Flask-Cache還提供了另一個裝飾器方法”cache.memoize()”,它與”cache.cached()”的區別就是它會將函數的參數也放在緩存項的鍵值中:

@cache.memoize(timeout=50)
def create_list(num):
    print 'method create_list called'
    l = []
    for i in range(num):
        l.append(str(i))
    return l
 
@app.route('/list/<int:num>')
def list(num):
    return ', '.join(create_list(num))

我們再次訪問”/list”地址,對於不同的參數,”method called”會一直在控制台上打印出,而對於相同的參數,第二次就不會打印了。所以對於帶參數的函數,你要使用”cache.memoize()”裝飾器,而對於不帶參數的函數,它同”cache.cached()”基本上一樣。”cache.memoize()”裝飾器也有三個參數,”timeout”和”unless”參數同”cache.cached()”一樣,就是第二個參數”make_name”比較特別。它是一個回調函數,傳入的是被裝飾的函數名,返回是一個字符串,會被作為緩存項鍵值的一部分,如果不設,就直接使用函數名。

刪除緩存

對於普通緩存,你可以使用”delete()”方法來刪除緩存項,而對於”memoize”緩存,你需要使用”delete_memoized”方法。如果想清除所有緩存,可以使用”clear()”方法。

cache.delete('get_list')                     # 刪除'get_list'緩存項
cache.delete_many('get_list', 'view_hello')  # 同時刪除'get_list'和'view_hello'緩存項
cache.delete_memoized('create_list', 5)      # 刪除調用'create_list'函數並且參數為5的緩存項
cache.clear()                                # 清理所有緩存

Jinja2模板中使用緩存

其實在Jinja2模板中,我們還可以使用”{% cache %}”語句來緩存模板代碼塊:

{% cache 50, 'temp' %}
<p>This is under cache</p>
{% endcache %}

這樣”{% cache %}”和”{% endcache %}”語句中所包括的內容就會被緩存起來。”{% cache %}”語句的第一個參數是”timeout”過期時間,默認為永不過期;第二個參數指定了緩存項的鍵值,如果不設,鍵值就是”模板文件路徑”+”緩存塊的第一行”。上例中,我們設了鍵值是”temp”,然后在代碼中,我們可以這樣獲取緩存項實際的鍵值:

from flask_cache import make_template_fragment_key
key = make_template_fragment_key('temp')

打印出來看看,你會發現實際的鍵值其實是”_template_fragment_cache_temp”。如果你要刪除該緩存項,記得要傳入實際的鍵值,而不是模板上定義的’temp’。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM