2013-03-12 2 views
6

Je souhaite utiliser un cache local de thread en mémoire pour une valeur de la base de données qui ne va pas changer au cours d'un cycle de demande/réponse, mais qui est appelé des centaines (potentiellement des milliers) de fois. Ma compréhension limitée est que l'utilisation d'une variable "global"/module est une façon d'implémenter ce type de cache.Les variables "globales" (module) python sont-elles locales?

par exemple:

#somefile.py 

foo = None 

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

Je me demande si l'utilisation de ce type de « global » est thread-safe en python, et que je peux donc être à l'aise que get_foo_from_db() sera appelé exactement une fois par demande/cycle de réponse dans django (en utilisant soit runserver ou gunicorn + gevent). Est-ce que ma compréhension est correcte? Cette chose est appelée assez que même l'utilisation de memcached pour stocker la valeur va être un goulot d'étranglement (je le profile en ce moment même).

Répondre

3

Non, vous avez tort sur deux points.

Tout d'abord, l'utilisation de "threads" est un peu vague ici. En fonction de la configuration de son serveur, Django peut être servi en utilisant des threads ou des processus ou les deux (voir le mod_wsgi documentation pour une discussion complète). S'il n'y a qu'un seul thread par processus, vous pouvez garantir qu'une seule instance d'un module sera disponible pour chaque processus. Mais cela dépend fortement de cette configuration.

Même ainsi, il n'est toujours pas possible qu'il y ait "exactement un" appel à cette fonction par cycle de demande/réponse. En effet, la durée de vie d'un processus est entièrement indépendante à ce cycle. Un processus durera pour plusieurs demandes, de sorte que la variable persistera pour toutes ces demandes.

+0

Cela a du sens. Question de suivi ici: http://stackoverflow.com/questions/15365780/how-to-implement-thread-safe-in-memory-cache-of-value-in-django –

3

Non, l'accès aux globals n'est pas sécurisé pour les threads. Les threads n'ont pas leur propre copie des globals, les globals sont partagés entre les threads.

Le code:

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

compile plusieurs déclarations bytecode 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) 

Un commutateur de fil peut se produire après chaque exécution de bytecode, donc un autre thread pourrait modifier fooaprès avoir testé il.

Questions connexes