2016-01-11 16 views
8

Ich versuche eine minimale Flask-Anwendung zu erstellen, die eventlet verwendet, um auf gleichzeitige Anfragen sofort zu reagieren, statt zu blockieren und auf eine Anfrage nach der anderen zu antworten (wie der standard Flask Debugging Webserver tut).Reagieren auf gleichzeitige Anfragen mit Flask und Eventlet

Voraussetzungen:

pip install Flask 
pip install eventlet 

Von meinem Verständnis von dem, was ich bisher im Internet zu finden, sollte es so funktionieren:

# 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) 

Wenn diese Datei ausgeführt wird, dann http://localhost:5000/longTask in einem Web-Browser öffnen Registerkarte und während es noch verarbeitet Öffnen eines anderen Tab mit http://localhost:5000/shortTask, würde ich erwarten, dass die zweite Registerkarte sofort zurück, während die erste Registerkarte noch geladen wird. Ähnlich wie bei der Ausführung auf dem Standard-Werkzeug-Server von Server kehrt die zweite Registerkarte jedoch nur zurück, nachdem die erste nach 30 Sekunden beendet wurde.

Was ist hier falsch? By the way, das, was gegeben wird, würde üblicherweise bezeichnet als „Produktion bereit Webserver“ für Flask, dass es nur wenige gleichzeitige Benutzer sind (höchstens 5) zu erwarten?

Übrigens, wenn ich the Flask-socketio library benutze, um den Webserver zu starten, der, entsprechend der Dokumentation, automatisch eventlet auswählt, wenn es installiert ist, dann funktioniert es wie erwartet.

Komplettes Beispiel mit Flask-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) 

Antwort

11

Wenn Sie app.run(debug=True) ausgeführt werden Sie explizit Flask sagen Ihre Anwendung auf dem Entwicklungs-Webserver ausgeführt werden, die auf Werkzeug basiert. Es spielt keine Rolle, dass Sie Eventlet geladen haben.

Wenn Sie Ihre Anwendung auf dem eventlet Web-Server ausführen möchten, müssen Sie einen eventlet Web-Server starten, die nach the documentation wird wie folgt gestartet:

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

Dies ist mehr oder weniger, was socketio.run() tut in meiner Flask-SocketIO-Erweiterung, mit ein wenig mehr Komplexität, um SSL optional zu handhaben. Die Codezeilen, die das tun, sind: https://github.com/miguelgrinberg/Flask-SocketIO/blob/539cd158f49ce085151911cb63edbacd0fa37173/flask_socketio/init.py#L391-L408. Wenn Sie sich in diesen Zeilen umsehen, werden Sie feststellen, dass es drei verschiedene Startup-Codestücke gibt, einen für das Werkzeug, einen für das Eventlet und einen für das Gevent. Sie sind alle verschieden.

+0

Ausgezeichnet! Das Flask-App-Objekt an den 'wsgi.server'-Befehl übergeben zu müssen, war mir aus dem Beispiel in den Eventlet-Dokumenten nicht klar, daher war dieses Flask-basierte Beispiel sehr hilfreich. – Dirk

2
import eventlet 
eventlet.monkey_patch() 

Wird nicht auf magische Weise Ihren Code in eine Multi-Thread-Tier verwandeln, die Anforderung asynchron verarbeiten kann (es ist immer noch ziemlich magisch und fantastisch). Wie Sie in this example sehen können, müssen Sie den wsgi Server mit eventlet wsgi's implementation starten.

Wenn Sie eine Standardlösung wollen, müssen Sie einen Blick auf, wie nginx und uwsgi verwenden Kolben Anwendung zu starten. Sie könnten auch an dem Projekt Spawning interessiert sein, das den Aufwand für die Erstellung eines vollständigen Multithread-WS-Handlers nutzt.

+0

Okay, ich sehe, Schalten in Tier-Modus ist nicht so einfach. Wie geht es dann mit "flaschen-sockelio"? Zumindest unter "Deployment/Embedded Server" [in der Dokumentation] (https://flask-socketio.readthedocs.org/en/latest/) sagt, es 'Beachten Sie, dass socketio.run (app) läuft eine Produktion bereit Server, wenn Eventlet oder Gevent sind installiert.', ohne ins Detail zu gehen. Seit uWsgi/NGINX [ist etwas Arbeit zu tun] (https://www.digitalcean.com/community/tutorials/how-to-serve-flask-applications-with-uwsgi-and-nginx-on-ubuntu- 14-04), besteht ein Nachteil darin, 'flask-socketio' zu verwenden, wie oben beschrieben? – Dirk