2

ローカル以外のWebサイト全体を要求する必要があるFlaskWebアプリケーションを作成しようとしていますが、Webサイトはそれほど頻繁に変更されないため、処理を高速化する目的でキャッシュできるかどうか疑問に思いました。しかし、私はそれでも1日1回程度キャッシュを更新したいと思っています。

とにかく、私はそれを調べて、Flask-Cacheを見つけました。これは、私が望んでいたことを実行しているように見えたので、適切な変更を加えて、これを追加することを思いつきました。

from flask.ext.cache import Cache
[...]
cache = Cache()
[...]
cache.init_app(app)
[...]
@cache.cached(timeout=86400, key_prefix='content')
def get_content():
    return lxml.html.fromstring(urllib2.urlopen('http://WEBSITE.com').read())

次に、次のように処理を進めるためにコンテンツを必要とする関数から呼び出しを行います。

content = get_content()

今では、呼び出しが行われるたびにキャッシュされたlxml.htmlオブジェクトを再利用することを期待していますが、それは私が見ているものではありません。オブジェクトのIDは、呼び出しが行われるたびに変更され、スピードアップはまったくありません。それで、Flask-Cacheが何をするのか誤解しましたか、それともここで何か間違ったことをしていますか?代わりにメモ化デコレータを使用してみました。タイムアウトを減らすか、すべて一緒に削除しようとしましたが、何も違いがないようです。

ありがとう。

4

1 に答える 1

6

デフォルトCACHE_TYPEではnull、これによりNullCache-が得られるため、観察したキャッシュはまったく取得されません。ドキュメントはこれを明示していませんが、ソースのこの行は次のようにCache.init_appしています。

self.config.setdefault('CACHE_TYPE', 'null')

実際にキャッシュCacheを使用するには、適切なキャッシュを使用するようにインスタンスを初期化します。

cache = Cache(config={'CACHE_TYPE': 'simple'})

余談ですが、これは開発とテスト、およびこの例には最適ですが、本番環境では使用しないでくださいSimpleCacheのようなもの、MemCachedまたはRedisCacheはるかに良いでしょう

これで、実際のキャッシュが配置された状態で、次の問題が発生します。2回目の呼び出しで、キャッシュされたlxml.htmlオブジェクトはから取得されますがCache、これらのオブジェクトはキャッシュできないため、壊れています。Stacktraceは次のようになります。

Traceback (most recent call last):
  File "/home/day/.virtualenvs/so-flask/lib/python2.7/site-packages/flask/app.py", line 1701, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/day/.virtualenvs/so-flask/lib/python2.7/site-packages/flask/app.py", line 1689, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/home/day/.virtualenvs/so-flask/lib/python2.7/site-packages/flask/app.py", line 1687, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/day/.virtualenvs/so-flask/lib/python2.7/site-packages/flask/app.py", line 1360, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/day/.virtualenvs/so-flask/lib/python2.7/site-packages/flask/app.py", line 1358, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/day/.virtualenvs/so-flask/lib/python2.7/site-packages/flask/app.py", line 1344, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/day/q12030403.py", line 20, in index
    return "get_content returned: {0!r}\n".format(get_content())
  File "lxml.etree.pyx", line 1034, in lxml.etree._Element.__repr__ (src/lxml/lxml.etree.c:41389)

  File "lxml.etree.pyx", line 881, in lxml.etree._Element.tag.__get__ (src/lxml/lxml.etree.c:39979)

  File "apihelpers.pxi", line 15, in lxml.etree._assertValidNode (src/lxml/lxml.etree.c:12306)

AssertionError: invalid Element proxy at 3056741852

したがって、lxml.htmlオブジェクトをキャッシュする代わりに、単純な文字列(ダウンロードしたWebサイトのコンテンツ)をキャッシュし、それを再解析してlxml.html毎回新しいオブジェクトを取得する必要があります。毎回他のWebサイトにアクセスする必要がないため、キャッシュは引き続き役立ちます。これは、機能するソリューションを示すための完全なプログラムです。

from flask import Flask
from flask.ext.cache import Cache
import time
import lxml.html
import urllib2

app = Flask(__name__)

cache = Cache(config={'CACHE_TYPE': 'simple'})
cache.init_app(app)

@cache.cached(timeout=86400, key_prefix='content')
def get_content():
    app.logger.debug("get_content called")
#    return lxml.html.fromstring(urllib2.urlopen('http://daybarr.com/wishlist').read())
    return urllib2.urlopen('http://daybarr.com/wishlist').read()

@app.route("/")
def index():
    app.logger.debug("index called")
    return "get_content returned: {0!r}\n".format(get_content())

if __name__ == "__main__":
    app.run(debug=True)

プログラムを実行し、に2つの要求を行うとhttp://127.0.0.1:5000/、この出力が得られます。get_contentコンテンツはキャッシュから提供されるため、2回目は呼び出されないことに注意してください。

 * Running on http://127.0.0.1:5000/
 * Restarting with reloader
--------------------------------------------------------------------------------
DEBUG in q12030403 [q12030403.py:20]:
index called
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
DEBUG in q12030403 [q12030403.py:14]:
get_content called
--------------------------------------------------------------------------------
127.0.0.1 - - [21/Dec/2012 00:03:28] "GET / HTTP/1.1" 200 -
--------------------------------------------------------------------------------
DEBUG in q12030403 [q12030403.py:20]:
index called
--------------------------------------------------------------------------------
127.0.0.1 - - [21/Dec/2012 00:03:33] "GET / HTTP/1.1" 200 -
于 2012-12-22T20:30:01.070 に答える