Sono impegnato a scrivere un piccolo server di gioco per provare il pallone. Il gioco espone una API tramite REST agli utenti. È facile per gli utenti eseguire azioni e interrogare i dati, tuttavia mi piacerebbe servire il "mondo di gioco" al di fuori del ciclo app.run() per aggiornare le entità di gioco, ecc. Dato che Flask è implementato in modo così pulito, mi piacerebbe per vedere se c'è un modo Flask per farlo.Come posso aggiungere un thread in background alla beuta?
risposta
I thread aggiuntivi devono essere avviati dalla stessa app richiamata dal server WSGI.
L'esempio seguente crea un thread in background che viene eseguito ogni 5 secondi e gestisce le strutture di dati che sono anche disponibili per le funzioni instradate di Flask.
import threading
import atexit
from flask import Flask
POOL_TIME = 5 #Seconds
# variables that are accessible from anywhere
commonDataStruct = {}
# lock to control access to variable
dataLock = threading.Lock()
# thread handler
yourThread = threading.Thread()
def create_app():
app = Flask(__name__)
def interrupt():
global yourThread
yourThread.cancel()
def doStuff():
global commonDataStruct
global yourThread
with dataLock:
# Do your stuff with commonDataStruct Here
# Set the next thread to happen
yourThread = threading.Timer(POOL_TIME, doStuff,())
yourThread.start()
def doStuffStart():
# Do initialisation stuff here
global yourThread
# Create your thread
yourThread = threading.Timer(POOL_TIME, doStuff,())
yourThread.start()
# Initiate
doStuffStart()
# When you kill Flask (SIGTERM), clear the trigger for the next thread
atexit.register(interrupt)
return app
app = create_app()
chiamare da Gunicorn con qualcosa di simile:
gunicorn -b 0.0.0.0:5000 --log-config log.conf --pid=app.pid myfile:app
Ho trovato che questo è problematico quando si utilizza la funzionalità di auto-ricarica di Flask (un nuovo thread è stato creato su ogni ricarica). Per risolvere il problema, ho usato [werkzeug.serving.is_running_from_reloader] (http://werkzeug.pocoo.org/docs/0.10/serving/#werkzeug.serving.is_running_from_reloader) per crearlo solo quando l'app non è in esecuzione dal reloader . – raffomania
@caio dovrebbe essere "con dataLock:" capitale L sopra. –
Questa è una bella soluzione; aiuta ad affrontare le applicazioni di flask che usano moduli di multiprocessing o threading. Mi piace. –
Sembra che ci sia a hackish way to do it, ma non penso che questo sia supportato tecnicamente.
Ho trovato anche this answer, che parla dell'utilizzo di boccetta di sedano per questo.
+1 - sedano o qualche altro sistema di coda di attività è l'ideale per questo genere di cose - generalmente si ha meno controllo su thread o sotto processi (poiché il processo genitore può essere raccolto dal server senza preavviso). –
Oltre a utilizzare le discussioni puri o la coda di sedano (si noti che fiasco-sedano non è più necessario), si potrebbe anche avere una guardare pallone-apscheduler:
https://github.com/viniciuschiele/flask-apscheduler
Un semplice esempio copiato da https://github.com/viniciuschiele/flask-apscheduler/blob/master/examples/jobs.py:
from flask import Flask
from flask_apscheduler import APScheduler
class Config(object):
JOBS = [
{
'id': 'job1',
'func': 'jobs:job1',
'args': (1, 2),
'trigger': 'interval',
'seconds': 10
}
]
SCHEDULER_API_ENABLED = True
def job1(a, b):
print(str(a) + ' ' + str(b))
if __name__ == '__main__':
app = Flask(__name__)
app.config.from_object(Config())
scheduler = APScheduler()
# it is also possible to enable the API directly
# scheduler.api_enabled = True
scheduler.init_app(app)
scheduler.start()
app.run()
Intendi qualcosa come Flask-Admin? Oppure, se stai utilizzando un ORM (SQL-Alchemy), puoi semplicemente creare una nuova sessione db per interrogare il database anche se l'applicazione è in esecuzione. – reptilicus
Se è effettivamente necessario eseguire molti calcoli, è possibile utilizzare il modulo dei processi secondari e generare semplicemente nuovi processi per eseguire tale calcolo aggiuntivo. – Maus
Questo è un piano, tuttavia il sottoprocesso manipolerà le strutture di dati, che vorresti accedere e impostare tramite l'api della beuta esposta. Non incontrerò problemi? – Marinus