2015-09-28 20 views
19

Nella mia app lo stato di un oggetto comune viene modificato facendo richieste e la risposta dipende dallo stato.Le variabili globali sono thread safe in beuta?

class SomeObj(): 
    def __init__(self, param): 
     self.param = param 
    def query(self): 
     self.param += 1 
     return self.param 

global_obj = SomeObj(0) 

@app.route('/') 
def home(): 
    flash(global_obj.query()) 
    render_template('index.html') 

Se si esegue questo sul mio server di sviluppo, mi aspetto di ottenere 1, 2, 3 e così via. Se le richieste vengono fatte da 100 diversi clienti contemporaneamente, qualcosa può andare storto? Il risultato atteso è che i 100 diversi clienti ciascuno vedono un numero unico da 1 a 100. O sarà qualcosa di simile accada:

  1. client 1 query. self.param viene incrementato di 1.
  2. Prima che l'istruzione di reso possa essere eseguita, il thread passa al client 2. self.param viene nuovamente incrementato.
  3. Il thread torna al client 1 e il client restituisce il numero 2, ad esempio.
  4. Ora il filo si sposta al client 2 e restituisce lui/lei il numero 3.

Dato che c'erano solo due clienti, i risultati attesi sono stati 1 e 2, non 2 e 3. è stato saltato un numero.

Questo accadrà realmente mentre aumento la richiesta? Quali alternative a una variabile globale dovrei guardare?

risposta

20

Non è possibile utilizzare le variabili globali per conservare questo tipo di dati. Non solo non è thread-safe, non è il processo sicuro ei server WSGI nella produzione generano più processi. Non solo i tuoi conteggi sarebbero sbagliati se stavi usando i thread per gestire le richieste, ma anche a seconda di quale processo ha gestito la richiesta.

Utilizzare un'origine dati fuori da Flask per conservare i dati globali. Un database, memcached o redis sono tutte aree di archiviazione separate appropriate, a seconda delle esigenze. Puoi anche utilizzare la sessione per dati semplici che sono per utente.


Il server di sviluppo è single thread, processo singolo per impostazione predefinita. Non vedrai il comportamento che descrivi poiché ogni richiesta verrà gestita in modo sincrono. Abilita thread o processi e lo vedrai. app.run(threaded=True) o app.run(processes=10).


Alcuni server WSGI possono supportare gevent o un altro operatore asincrono. Le variabili globali non sono ancora affidabili perché non c'è ancora protezione contro la maggior parte delle condizioni di gara. È ancora possibile avere uno scenario in cui un lavoratore ottiene un valore, produce, un altro lo modifica, produce, quindi anche il primo operatore lo modifica.

-1

Un rapido e sporco, non thread-safe meccanismo:

app = Flask(__name__) 
    app.speed = 0.0 # add new properties to the instance 
    app.last_check_tm = time.time() 
    ... 

Ho una domanda in cui FASK è in esecuzione come un server wifi locale su un Raspberry Pi per consentire agli utenti di connettersi utilizzando un telefono cellulare. L'applicazione deve "ricordare" i dati e il tempo che intercorre tra le richieste e utilizzare queste informazioni poiché raccoglie informazioni dagli input hardware locali (dove session non è disponibile). NB questo è solo un uso in cui Flask serve solo un utente alla volta.

MODIFICA. Come sottolineato sotto questo approccio è una cattiva idea.sqlite ha un'opzione per creare il database in memoria che impedisce la scrittura ripetuta su scheda SD (che è quello che stavo cercando di evitare) PS Purtroppo sqlite non può essere eseguito in un thread diverso, quindi questa semplice soluzione probabilmente non funzionerà per io e io avremo bisogno di un sistema più complicato (probabilmente qualcosa sulla falsariga dell'esecuzione di Fask in una sottoprocessing differente.Processo e invio di informazioni dentro e fuori con oggetti Queue, un po 'disordinati!) Come ha fatto notare davidism sqlite può farlo e mi sono scambiato per questo metodo molto migliore. Creata la connessione utilizzando conn = sqlite3.connect(':memory:',check_same_thread=False)

+1

Questo non sembra rispondere alla domanda. Inoltre, non funzionerà più in sicurezza quando viene rilasciato Flask 1.0, che passa automaticamente ai thread di abilitazione. Non farlo. Utilizzare un db SQLite se è necessario qualcosa di leggero e disponibile localmente. – davidism

+0

@davidism ringraziamenti Mi sbagliavo sulla limitazione di sqlite3. Inoltre ho preso in considerazione l'idea di togliere completamente la mia risposta. Come dici tu, non risponde affatto all'OP. Tuttavia, dopo un po 'di googling questa è stata l'informazione più pertinente e utile che ho trovato quindi ho pensato che questo potesse aiutare qualcuno ad un certo punto. Poiché StackOverflow è diventato la fonte n. 1 di * tutte * le risposte di programmazione, le domande devono essere interpretate in termini della query di google che attiene qui piuttosto che la formulazione effettiva dell'OP! – paddyg

+0

Una risposta a "sono variabili globali thread safe" che inizia con "un meccanismo non thread safe" non è esplicitamente una risposta alla domanda, e non è di grande aiuto. Se vuoi rispondere autonomamente a una domanda su come utilizzare SQLite o una singola applicazione con thread su un Raspberry Pi, fallo, non metterla in una domanda non correlata. – davidism

Problemi correlati