2013-03-12 5 views
6

私は、要求/応答サイクル中に変更されないが、数百(潜在的には何千もの)回呼び出されるデータベースからの値に対して、メモリ内のスレッドローカルキャッシュを使用したいと考えています。私の限られた理解は、 "グローバル" /モジュール変数を使用することは、このタイプのキャッシュを実装する1つの方法です。Pythonの "グローバル"(モジュール)変数はスレッドローカルですか?

例:

#somefile.py 

foo = None 

def get_foo(request): 
    global foo 
    if not foo: 
    foo = get_foo_from_db(request.blah) 
    return foo 

私は「グローバル」のこのタイプを使用してPythonでスレッドセーフであるかどうかを思ったんだけど、それはので、私はget_foo_from_db()はリクエストごとに1回だけ呼び出されますことを快適にすることができます/ djangoの応答サイクル(runserverまたはgunicorn + geventを使用)。私の理解は正しいのですか?このことは、値を格納するためにmemcachedを使用してもボトルネックになるほど十分に呼び出されます(私が話すようにプロファイリングしています)。

答えて

3

いいえ、2つのカウントで間違っています。

まず、「スレッド」の使用は少し曖昧です。サーバの設定方法によっては、スレッドやプロセス、あるいはその両方を使ってDjangoを提供することができます(詳細はmod_wsgi documentationを参照してください)。プロセスごとに1つのスレッドがある場合、モジュールの1つのインスタンスだけが各プロセスで使用できることを保証できます。しかし、それはその構成に大きく依存しています。

でも、要求/応答サイクルごとにその関数への「正確に1回」の呼び出しが行われることはありません。これは、プロセスの寿命がで、そのサイクルにまったく関係ないであるためです。プロセスは複数の要求を処理するため、そのすべての要求に対して変数が保持されます。

+0

意味があります。ここに質問をフォローアップ:http://stackoverflow.com/questions/15365780/how-to-implement-thread-safe-in-memory-cache-of-value-in-django –

3

いいえ、グローバルへのアクセスはスレッドセーフではありません。スレッドは独自のグローバルコピーを取得せず、グローバルはスレッド間で共有されます。

コード:

if not foo: 
    foo = get_foo_from_db(request.blah) 

は、いくつかのPythonのバイトコードステートメントにコンパイルされます。

2   0 LOAD_FAST    1 (foo) 
       3 POP_JUMP_IF_TRUE  24 

    3   6 LOAD_GLOBAL    0 (get_foo_from_db) 
       9 LOAD_FAST    0 (request) 
      12 LOAD_ATTR    1 (blah) 
      15 CALL_FUNCTION   1 
      18 STORE_FAST    1 (foo) 
      21 JUMP_FORWARD    0 (to 24) 

スレッドスイッチはそれぞれ、すべてのバイトコードの実行後に発生する可能性がありますので、あなたがテストした後、別のスレッドがfooを変更することができそれはです。

関連する問題