2013-03-12 12 views
6

Mi piacerebbe utilizzare una cache locale thread in memoria per un valore dal database che non cambierà durante un ciclo di richiesta/risposta, ma viene chiamato centinaia (potenzialmente migliaia) di volte. La mia comprensione limitata è che l'utilizzo di una variabile "globale"/modulo è un modo per implementare questo tipo di cache.Le variabili python "globali" (modulo) sono thread locali?

esempio:

#somefile.py 

foo = None 

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

Mi chiedo se l'utilizzo di questo tipo di "globale" è thread-safe in python, e che quindi posso essere comodo che get_foo_from_db() verrà chiamato una sola volta per ogni richiesta/ciclo di risposta in django (usando runserver o gunicorn + gevent). La mia comprensione è corretta? Questa cosa viene chiamata abbastanza che persino l'uso di memcached per memorizzare il valore sarà un collo di bottiglia (lo sto profilando mentre parliamo).

risposta

3

No, ti sbagli su due punti.

In primo luogo, l'uso di "discussioni" è un po 'vago qui. A seconda di come è configurato il suo server, Django può essere servito usando thread o processi o entrambi (vedere lo mod_wsgi documentation per una discussione completa). Se esiste un singolo thread per processo, è possibile garantire che solo una istanza di un modulo sarà disponibile per ogni processo. Ma questo è altamente dipendente da quella configurazione.

Anche così, non è ancora il caso che ci sarà "esattamente una" chiamata a quella funzione per ciclo di richiesta/risposta. Questo perché la durata di un processo è interamente indipendente per quel ciclo. Un processo durerà per più richieste, quindi la variabile persisterà per tutte quelle richieste.

+0

Ha senso. Domanda successiva: http://stackoverflow.com/questions/15365780/how-to-implement-thread-safe-in-memory-cache-of-value-in-django –

3

No, l'accesso ai globals non è thread-safe. I thread non ottengono la propria copia di globals, i globals sono condivisi tra i thread.

Il codice:

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

compila a diverse istruzioni pitone bytecode:

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 interruttore thread può verificarsi dopo ogni esecuzione bytecode, quindi un altro filo potrebbe alterare foodopo aver testato it.

Problemi correlati