Python Tornado – Verwirrt, wie man eine Sperrfunktion in eine nicht blockierende Funktion umwandelt

Angenommen, ich habe eine lange laufende Funktion:

def long_running_function(): result_future = Future() result = 0 for i in xrange(500000): result += i result_future.set_result(result) return result_future 

Ich habe eine Funktion in einem Handler, der den Benutzer mit dem obigen Ergebnis einer for-Schleife druckt, die die ganze Zahl im xrange hinzufügt:

 @gen.coroutine def get(self): print "start" self.future = long_running_function() message = yield self.future self.write(str(message)) print "end" 

Wenn ich den obigen Code auf zwei Webbrowsern gleichzeitig laufe, bekomme ich:

Anfang

Ende

Anfang

Ende

Was scheint zu blockieren. Aus meinem Verständnis, die @gen.coroutine und die yield Anweisung nicht blockieren die IOLoop in der get-Funktion, aber wenn irgendwelche Funktionen, die innerhalb der Co-Routine, die blockiert ist, dann blockiert es die IOLoop.

Also das andere, was ich tat, ist, die long_running_function in einen Callback zu verwandeln und stattdessen die yield gen.Task verwenden.

 @gen.coroutine def get(self): print "start" self.future = self.long_running_function message = yield gen.Task(self.future, None) self.write(str(message)) print "end" def long_running_function(self, arguments, callback): result = 0 for i in xrange(50000000): result += i return callback(result) 

Das schneidet auch nicht, es gibt mir:

Anfang

Ende

Anfang

Ende

Ich kann Threads verwenden, um diese parallel auszuführen, aber es scheint nicht der Weg zu gehen, denn ich könnte eine Menge von Threads öffnen, und nach Tornados Benutzerhandbuch kann es teuer sein.

Wie schreibt man Async-Bibliotheken für Tornado?

2 Solutions collect form web for “Python Tornado – Verwirrt, wie man eine Sperrfunktion in eine nicht blockierende Funktion umwandelt”

Wenn die Sperrfunktion CPU-gebunden ist (wie es bei / xrange-Beispiel ist), dann sind Threads (oder Prozesse) der einzige Weg, um es nicht blockieren zu lassen. Das Erstellen eines Threads pro eingehenden Anforderung ist teuer, aber ein kleiner ThreadPoolExecutor, der alle CPU-gebundenen Operationen verarbeiten soll, ist nicht.

Um eine Funktion nicht blockieren zu lassen, ohne Threads zu verwenden, muss die Funktion ereignisgesteuert sein : Sie muss auf ein externes Ereignis warten (z. B. Netzwerk I / O), damit es bei diesem Ereignis aufgewacht werden kann.

Ich bin derzeit kämpfen, um eine Web-Schnittstelle für meine Simulation Programm mit Tornado und seine WebSocket-Funktion hinzufügen. Mein Simulationsprogramm ist rechnerisch intensiv, dh CPU-gebundene Aufgabe wie von @ ben-darnell gesagt, die mit einem anderen Thread oder Prozess implementiert werden soll.

Nach vielen Untersuchungen denke ich, dass diese Ressourcen hilfreich sein können:

  • Tornado blockiert asynchrone Anfragen – Antwort von @koblas
  • Der Versuch, eine lange Sperrfunktion in Tornado in einer nicht blockierenden Weise zu nennen

Ich mache die ähnliche Implementierung jetzt, und werde diese Antwort aktualisieren, wenn ich mehr Fortschritt habe 🙂

  • Python Tornado Websocket Verbindungen noch offen, nachdem sie geschlossen wurden
  • Tornado [Errno 24] Zu viele offene Dateien [duplizieren]
  • Tornado Python als Dämon
  • Python JSON Encoder zur Unterstützung von datetime?
  • Holen Sie sich Python Tornado Version?
  • Arbeiter Beanstalkt Tornado im Docker-Container
  • Übergeben von Daten zwischen Klassen in Tweepy und Tornado WebSocket
  • Warteschlange und ProcessPoolExecutor in Tornado
  • Sockjs - Beispiel für die Implementierung von Räumen
  • Benutzer-Authentifizierung in Tornado-Webseiten-Anwendung
  • Überprüfen Sie alle Elemente mit einem Klick mit Tornado
  • Python ist die beste Programmiersprache der Welt.