Python Tornado - faire retour POST immédiatement en fonction async continue de fonctionner

StackOverflow https://stackoverflow.com/questions/3869421

  •  28-09-2019
  •  | 
  •  

Question

j'ai donc un gestionnaire ci-dessous:

class PublishHandler(BaseHandler):

    def post(self):
        message = self.get_argument("message")
        some_function(message)
        self.write("success")

Le problème que je suis face est que une_fonction () prend un certain temps pour exécuter et je voudrais la demande après de revenir tout de suite quand appelé et pour une_fonction () à exécuter dans un autre thread / processus si possible.

J'utilise db comme berkeley base de données et ce que je suis en train de faire est relativement simple.

J'ai une base de données d'utilisateurs chacun avec un filtre. Si le filtre correspond au message, le serveur envoie le message à l'utilisateur. Actuellement je teste avec des milliers d'utilisateurs et donc sur chaque publication d'un message via une demande après il est itérer des milliers d'utilisateurs de trouver un match. Ceci est ma mise en œuvre naïve de faire les choses et donc ma question. Comment puis-je faire mieux?

Était-ce utile?

La solution

Vous pourriez être en mesure d'accomplir cela en utilisant la méthode de IOLoop de votre add_callback comme ceci:

loop.add_callback(lambda: some_function(message))

Tornado exécutera le rappel dans le passage suivant IOLoop, qui peut (je dois creuser dans les entrailles de Tornado pour en être sûr, ou bien le tester) permettent la demande de remplir avant que le code est exécuté.

L'inconvénient est que ce code de longue durée que vous avez écrit faudra encore du temps pour exécuter, et cela peut finir par bloquer une autre demande. Ce n'est pas idéal si vous avez beaucoup de ces demandes venant à la fois.

La solution la plus à toute épreuve est de l'exécuter dans un thread séparé ou d'un processus. meilleurs chemin avec Python est d'utiliser un processus, en raison de la GIL (je vous recommande vivement la lecture sur que si vous n'êtes pas familier avec elle). Cependant, sur une machine monoprocesseur la mise en œuvre filetée fonctionnera tout aussi bien, et peut-être plus simple à mettre en œuvre.

Si vous allez la route filetée, vous pouvez construire un beau module « exécuteur async » avec un mutex, un fil et une file d'attente. Consultez le module multiprocessing si vous voulez aller la route à l'aide d'un processus distinct.

Autres conseils

Je l'ai essayé, et je crois que la demande ne se termine pas avant que les callbacks sont appelés.

Je pense qu'un hack sale serait d'appeler deux niveaux de add_callback, par exemple:.

  def get(self):
    ...
    def _defered():
      ioloop.add_callback(<whatever you want>)
    ioloop.add_callback(_defered)
    ...

Mais ce sont hacks au mieux. Je suis à la recherche d'une meilleure solution en ce moment, finira probablement avec une file d'attente de messages ou d'une solution de fil simple.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top