2016-01-11 24 views
8

Provo a configurare un'applicazione Minota che utilizza eventlet per rispondere istantaneamente alle richieste simultanee invece di bloccare e rispondere a una richiesta dopo l'altra (come fa il server di debug di debug standard Flask).Risposta alle richieste simultanee con Flask e eventlet

Prerequisiti:

pip install Flask 
pip install eventlet 

Dalla mia comprensione per quello che ho trovato finora su Internet, dovrebbe funzionare in questo modo:

# activate eventlet 
import eventlet 
eventlet.monkey_patch() 

from flask import Flask 

import datetime 
from time import sleep 

# create a new Flask application 
app = Flask(__name__) 

# a short running task that returns immediately 
@app.route('/shortTask') 
def short_running_task(): 
    start = datetime.datetime.now() 
    return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now()) 

# a long running tasks that returns after 30s 
@app.route('/longTask') 
def long_running_task(): 
    start = datetime.datetime.now() 
    sleep(30) 
    return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now()) 

# run the webserver 
if __name__ == '__main__': 
    app.run(debug=True) 

Quando si esegue questo file, poi aprire http://localhost:5000/longTask in un browser web scheda e mentre sta ancora elaborando l'apertura di un'altra scheda con http://localhost:5000/shortTask, mi aspetto che la seconda scheda venga restituita immediatamente mentre la prima scheda viene ancora caricata. Tuttavia, simile a quando si esegue questo sul server standard di Werkzeug, la seconda scheda ritorna solo dopo che il primo è finito dopo 30s.

Cosa c'è di sbagliato qui? Ad ogni modo, questo sarebbe quello che viene comunemente definito un "server web pronto per la produzione" per Flask, dato che ci sono solo pochi utenti concorrenti (5 al massimo)?

A proposito, quando uso the Flask-socketio library per eseguire il server Web che, in base alla documentazione, sceglie automaticamente eventlet se è installato, quindi funziona come previsto.

Esempio completo con la boccetta-socketio:

# activate eventlet 
import eventlet 
eventlet.monkey_patch() 

from flask import Flask 
from flask_socketio import SocketIO 

import datetime 
from time import sleep 

# create a new Flask application 
app = Flask(__name__) 

# activate Flask-socketio 
socketio = SocketIO(app) 

# a short running task that returns immediately 
@app.route('/shortTask') 
def short_running_task(): 
    start = datetime.datetime.now() 
    return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now()) 

# a long running tasks that returns after 30s 
@app.route('/longTask') 
def long_running_task(): 
    start = datetime.datetime.now() 
    sleep(30) 
    return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now()) 

# run the webserver with socketio 
if __name__ == '__main__': 
    socketio.run(app, debug=True) 

risposta

11

Quando si esegue app.run(debug=True) si indica esplicitamente a Flask di eseguire l'applicazione sul server Web di sviluppo, che è basato su Werkzeug. Non importa che tu abbia caricato l'eventlet.

Se si desidera eseguire l'applicazione sul server eventlet web, è necessario avviare un server web eventlet, che secondo the documentation viene avviato come segue:

wsgi.server(eventlet.listen(('', 8000)), your_app) 

Questo è più o meno quello che socketio.run() fa nella mia estensione Flask-SocketIO, con un po 'più di complessità per gestire opzionalmente SSL. Le righe di codice che fanno questo sono: https://github.com/miguelgrinberg/Flask-SocketIO/blob/539cd158f49ce085151911cb63edbacd0fa37173/flask_socketio/init.py#L391-L408. Se guardi intorno a queste linee, vedrai che ci sono tre diversi blocchi di codice di avvio, uno per werkzeug, uno per eventlet e uno per gevent. Sono tutti diversi.

+0

Eccellente! Il fatto di dover passare l'oggetto app Flask al comando 'wsgi.server' non mi è stato chiaro dall'esempio nei documenti dell'eventolet, quindi questo esempio basato su Flask è stato molto utile. – Dirk

2
import eventlet 
eventlet.monkey_patch() 

non magicamente trasformare il codice in una bestia multithread in grado di gestire la richiesta in modo asincrono (è ancora abbastanza magico e impressionante).

Come si può vedere in this example, è necessario avviare il server wsgi utilizzando eventlet wsgi's implementation.

Se si desidera una soluzione standard, vedere come utilizzare nginx e uwsgi per avviare l'applicazione del pallone. Potresti anche essere interessato al progetto Spawning che sfrutta la sofferenza della creazione di un gestore wsgi multithread completo.

Problemi correlati