L'exécution d'une async tâche en arrière-plan dans la Tornade
La lecture de la Tornade de la documentation, il est très clair comment appeler une fonction async pour retourner une réponse:
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")
Ce qui manque, c'est comment un appel sera fait de manière asynchrone à une tâche de fond qui n'a pas de pertinence à la demande actuelle:
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")
Ce code devrait fonctionner, sauf qu'il fonctionne de manière synchrone et la demande attend jusqu'à ce qu'il soit fini.
Quel est le droit façon asynchrone appel de cette tâche, tout juste de retour à la demande actuelle?
Vous devez vous connecter pour publier un commentaire.
Mise à jour: Depuis Tornade 4.0 (juillet 2014), ci-dessous la fonctionnalité est disponible dans les IOLoop.spawn_callback méthode.
Malheureusement c'est le genre de difficile. Vous avez besoin à la fois de se détacher de la tâche en arrière-plan de la demande actuelle (de sorte qu'une défaillance dans la tâche d'arrière-plan n'entraîne pas une exception aléatoire jeté dans la demande) et de s'assurer que quelque chose est à l'écoute de la tâche en arrière-plan du résultat (pour se connecter à ses erreurs, si rien d'autre). Cela signifie quelque chose comme ceci:
Quelque chose comme ce sera probablement ajouté à la tornade lui-même dans l'avenir.
Je recommande d'utiliser toro. Il fournit un moyen relativement simple mécanisme pour la création d'un arrière-plan de la file d'attente des tâches.
Le code suivant (à mettre queue.py par exemple), commence un simple "travailleur()" qui attend tout simplement jusqu'à ce qu'il y a quelque chose dans sa file d'attente. Si vous appelez
queue.add(function,async,*args,**kwargs)
cela ajoute un élément à la file d'attente qui va réveiller travailleur() qui lance la tâche.J'ai ajouté la async paramètre de sorte que cette mesure peut contribuer à des tâches de fond enveloppé dans @gen.coroutine et ceux sans.
Dans votre grande tornade application:
Et maintenant, vous pouvez planifier une tâche de fond tout simplement:
J'ai une tâche fastidieuse dans la requête post, peut-être plus que 30 minutes, mais le client de retour à un résultat immédiat.
Tout d'abord, j'ai utilisé IOLoop.current().spawn_callback. Il fonctionne! mais! Si la première demande de la tâche est en cours d'exécution, deuxième demande de tâche bloquée! Parce que toutes les tâches sont dans l'événement principal de la boucle lors de l'utilisation spawn_callback, donc d'une tâche d'exécution synchrone, d'autres tâches bloquées.
Dernier, j'utilise la tornade.simultanées. Exemple:
et visite http://127.0.0.1:8000, vous pouvez voir qu'il est exécuté ok:
Veulent aider tout le monde!
Il suffit de faire:
La
_background_task
coroutine renvoie uneFuture
qui est en suspens jusqu'à la coroutine est terminée. Si vous ne pas rendement de laFuture
, et au lieu simplement d'exécuter la ligne suivante immédiatement, puisget()
ne pas attendre pour_background_task
à la fin.Un détail intéressant est que, jusqu'à ce que
_background_task
finitions, il conserve une référence àself
. (N'oubliez pas d'ajouterself
comme un paramètre, par la manière.) Votre RequestHandler ne sera pas nettoyée jusqu'à ce que après_background_task
complète.Future
, le corps de la méthode fait exécuter?