2015-06-17 6 views
6

Ich habe flask verwendet, und einige meiner Routen-Handler starten Berechnungen, die einige Minuten dauern können. Mit dem Entwicklungsserver von flask kann ich app.run (threaded = True) verwenden und mein Server wird weiterhin auf andere Anfragen reagieren, während er diese mehrminütigen Berechnungen nicht durchführt.threading = True mit flask-socketio

Jetzt habe ich angefangen zu Flask-SocketIO und ich bin mir nicht sicher, wie das Äquivalent zu tun. Ich verstehe, dass ich bei jedem Start einer dieser Berechnungen explizit einen separaten Thread in Python erstellen kann. Ist das der einzige Weg? Oder gibt es etwas, das äquivalent zu threaded = True für flask-socket ist. (Oder, wahrscheinlicher, bin ich gerade völlig verwirrt.)

Danke für irgendeine Hilfe.

Antwort

13

Die Idee des Thread-Modus in Flask/Werkzeug ist, dass der Entwicklungsserver mehrere Anfragen gleichzeitig behandeln kann. Im Standardmodus kann der Server jeweils eine Anfrage bearbeiten. Wenn ein Client eine Anfrage sendet, während der Server bereits eine vorherige Anfrage bearbeitet, muss die zweite Anfrage warten, bis diese erste Anfrage abgeschlossen ist. Im Thread-Modus erzeugt Werkzeug für jede eingehende Anfrage einen Thread, sodass mehrere Anfragen gleichzeitig behandelt werden. Sie nutzen den Threading-Modus offensichtlich, um Anforderungen zu erhalten, deren Rückgabe sehr lange dauert, während der Server weiterhin auf andere Anforderungen reagiert.

Beachten Sie, dass dieser Ansatz schwer skalierbar ist, wenn Sie den Entwicklungs-Webserver in einen Produktions-Webserver verlagern. Für einen Worker-basierten Server müssen Sie eine feste Anzahl von Worker auswählen, und das gibt Ihnen die maximale Anzahl gleichzeitiger Anfragen, die Sie haben können.

Der alternative Ansatz besteht darin, einen Coroutine-basierten Server wie gevent zu verwenden, der vollständig von Flask unterstützt wird. Für gevent gibt es einen einzelnen Worker-Prozess, aber darin gibt es mehrere leichtgewichtige (oder "grüne") Threads, die sich kooperativ gegenseitig ausführen lassen. Der Schlüssel, um Dinge unter diesem Modell funktionieren zu lassen, ist sicherzustellen, dass diese grünen Threads die CPU-Zeit, die sie bekommen, nicht ausnutzen, weil nur eine gleichzeitig ausgeführt werden kann. Wenn dies richtig gemacht wird, kann der Server viel besser skalieren als mit dem oben beschriebenen Ansatz mit mehreren Mitarbeitern, und Sie können leicht Hunderte/Tausende von Clients auf diese Weise behandeln lassen.

So jetzt wollen Sie Flask-SocketIO verwenden, und diese Erweiterung erfordert die Verwendung von gevent. Falls der Grund für diese Anforderung nicht klar ist, verwendet SocketIO im Gegensatz zu HTTP-Anforderungen das WebSocket-Protokoll, das langlebige Verbindungen erfordert. Durch die Verwendung von gevent und green threads ist es möglich, eine potenziell große Anzahl von ständig verbundenen Clients zu haben, was mit mehreren Mitarbeitern nicht möglich wäre.

Das Problem ist Ihre lange Berechnung, die nicht auf den Gevent-Typ des Servers abgestimmt ist. Um es funktionieren zu lassen, müssen Sie sicherstellen, dass Ihre Berechnungsfunktion oft ergibt, so dass andere Threads eine Chance erhalten und nicht verhungern. Zum Beispiel, wenn Ihre Berechnungsfunktion eine Schleife in in, können Sie etwas tun:

def my_long_calculation(): 
    while some_condition: 
     # do some work here 

     # let other threads run 
     gevent.sleep() 

Die sleep() Funktion wird grundsätzlich Thread stoppen und wechseln auf andere Threads, die CPU benötigen. Irgendwann wird die Kontrolle an Ihre Funktion zurückgegeben und an diesem Punkt geht es weiter zur nächsten Iteration. Sie müssen sicherstellen, dass die Schlafanrufe nicht zu weit voneinander entfernt sind (da dies den Rest der Anwendung nicht reagieren lässt) oder nicht zu nahe (da dies die Berechnung verlangsamen kann).

So, um Ihre Frage zu beantworten, solange Sie in Ihrer langen Berechnung richtig ergeben, müssen Sie nichts Besonderes tun, um gleichzeitige Anfragen zu behandeln, da dies der normale Betriebsmodus von gevent ist.

Wenn aus irgendeinem Grund der Yield-Ansatz nicht möglich ist, müssen Sie möglicherweise darüber nachdenken, die CPU-intensiven Aufgaben auf einen anderen Prozess zu verlagern. Vielleicht Sellerie verwenden, um diese als Job-Warteschlange zu erledigen.

Entschuldigung für die langatmige Antwort. Hoffe das hilft!

+0

Vielen Dank für diese Antwort Miguel. (Ich hätte Ihnen früher gedankt, aber ich war im Urlaub.) Das ist sehr klar und hilfreich. –