Die Ausführung einer asynchronen hintergrund-task in Tornado
Lesen der Tornado-Dokumentation, es ist sehr klar, wie aufrufen, eine async-Funktion zum zurückgeben einer Reaktion:
class GenAsyncHandler(RequestHandler):
@gen.coroutine
def get(self):
http_client = AsyncHTTPClient()
response = yield http_client.fetch("http://example.com")
do_something_with_response(response)
self.render("template.html")
Was fehlt ist, wie sollte ein Anruf gemacht werden asynchron an ein hintergrund-task, die keinen Bezug zu der aktuellen Anforderung:
class GenAsyncHandler(RequestHandler):
@gen.coroutine
def _background_task():
pass # do lots of background stuff
@gen.coroutine
def get(self):
_dont_care = yield self._background_task()
self.render("template.html")
Dieser code würde funktionieren, außer, dass es läuft synchron und die Anfrage wartet, bis es fertig ist.
Was ist der Recht Weg, um asynchron aufrufen, diese Aufgabe unter sofortiger Rücksendung der aktuellen Anfrage?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Update: Seit Tornado 4.0 (Juli 2014), die unterhalb der Funktion steht in der IOLoop.spawn_callback Methode.
Leider ist es etwas schwierig. Sie brauchen, um beide zu trennen-hintergrund Aufgabe aus der aktuellen Anforderung (so dass ein Ausfall der hintergrund-tasks nicht Ergebnis in eine zufällige Ausnahme geworfen Anfrage) und sorgen dafür, dass etwas hört die hintergrund-task Ergebnis (anmelden seine Fehler, wenn nichts anderes). Dies bedeutet so etwas wie dieses:
Etwas wie dies wird wahrscheinlich Hinzugefügt werden, um die tornado selbst in der Zukunft.
Empfehle ich toro. Es bietet einen relativ einfachen Mechanismus für die Einrichtung eines hintergrund-Warteschlange von Aufgaben.
Den folgenden code (in queue.py zum Beispiel), startet eine einfache "Arbeiter ()", die einfach wartet, bis es ist etwas in seiner Warteschlange. Wenn Sie anrufen
queue.add(function,async,*args,**kwargs)
dies fügt ein Element in die Warteschlange, die aufwachen, Arbeiter (), die dann startet die Aufgabe.Habe ich den async-parameter so, dass diese Unterstützung von hintergrund-tasks-wrapped in @gen.coroutine und solche ohne.
In Ihrem Haupt-tornado-app:
Und nun können Sie planen, ein Boden zurück, die Aufgabe ganz einfach:
Ich habe eine zeitaufwändige Aufgabe in der post-Anforderung, vielleicht auch mehr als 30 Minuten brauchen, aber client benötigt Rückkehr sofort ein Ergebnis.
Erste, die ich verwendet,IOLoop.current().spawn_callback. Es funktioniert! aber! Wenn die erste Anforderung-task ausgeführt wird, wird die zweite Anforderung-task blockiert! Denn alle Aufgaben sind in Haupt-event-Schleife verwenden, wenn spawn_callback, so eine Aufgabe ist die synchrone Ausführung, andere Aufgaben blockiert.
Letzte, ich benutze tornado.gleichzeitige. Beispiel:
besuchen und http://127.0.0.1:8000, können Sie sehen, es ist ok:
Möchten allen zu helfen!
Einfach:
Den
_background_task
coroutine gibt eineFuture
ist ungelöst, bis die koroutine abgeschlossen. Wenn Sie nicht Ertrag derFuture
, und statt dessen einfach die nächste Zeile ausführen sofort, dannget()
nicht warten_background_task
fertig zu stellen.Interessantes detail ist, dass, bis
_background_task
Oberflächen, pflegt Sie einen Verweis aufself
. (Vergessen Sie nicht, fügen Sieself
als parameter, übrigens.) Ihre RequestHandler nicht Müll gesammelt, bis nach_background_task
abgeschlossen.Future
funktioniert die Methode Körper eigentlich laufen?