2013-01-12 5 views
3

J'ai une application tornade et je veux utiliser une bibliothèque de blocage pour accomplir quelque chose. Dans les cas où il n'est pas possible de réécrire la bibliothèque de manière asynchrone, comment l'exécuter en tornade? Par exemple, j'aimerais pouvoir mettre un décorateur @asynchronous sur un gestionnaire de requêtes, en commençant une fonction longue qui retournera une réponse une fois que c'est fait. Je ne peux pas simplement mettre un rappel. L'exemple le plus simple est bien sûr de savoir quelle est la bonne façon de dormir pendant 10 secondes sans bloquer le seul fil de la tornade?Exécution du code de blocage dans Tornado

+0

Pouvez-vous fournir plus d'informations sur la façon dont vous voulez bloquer la tornade? Parce que vous pouvez toujours faire 'time.sleep (10)' mais je suis sûr que vous voulez faire autre chose ... –

+0

@StevePeak merci, j'ai ajouté un autre paragraphe – abyx

+0

Drôle, j'ai ce même concept dans l'une de mes applications. Voir mon SO ici: http://stackoverflow.com/questions/13961863/tornado-web-http-request-blocks-other-requests-how-to-not-block-other-requests est votre problème lié à cela? De toute façon, j'aimerais vous aider. –

Répondre

2

Il semble que ce que je voulais était simplement créer un nouveau thread/processus, et que l'acte même de rappeler à une tornade qui doit être fait avec IOLoop.instance().add_callback

Plus d'informations sont disponibles here

+0

J'ai posté une question sur la performance de ce script. http://stackoverflow.com/questions/14306360/performance-of-asynchronous-request-handler-with-blocking-tasks-handled-by-work –

1

Essayez cet exemple ci-dessous.

import tornado.ioloop 
import tornado.web 
import time 

class MainHandler(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    def get(self, request): 
     if request is None: 
      self.application.go = False 
      self.write("Waiting for GET @ http://localhost:8888/go...<br>") 
      self.flush() 
      self._do_wait() 
     else: 
      self.application.go = True 
      self.finish('Thanks!') 

    def _do_wait(self, timeout_trys=10): 
     if self.application.go: 
      self.write('Finish') 
      self.finish() 
     else: 
      self.write("Sleeping 2 second, timeout_trys=%s<br>" % timeout_trys) 
      self.flush() 
      tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 2, 
       lambda: self._do_wait(timeout_trys-1)) 


application = tornado.web.Application([ 
    (r"/(\w+)?", MainHandler), 
]) 

if __name__ == "__main__": 
    application.listen(8888) 
    tornado.ioloop.IOLoop.instance().start() 
+0

merci, mais je pense que ce que je cherchais, c'est plus comme je l'ai montré dans ma réponse ici – abyx

+0

@abyx grande trouvaille! –

2

Le code de la réponse acceptée fait référence à is available on SO.

Une autre approche est détaillée dans un article de blog here, avec a full working gist. Voici un nouvel affichage du code à partir de l'essentiel:

from concurrent.futures import ThreadPoolExecutor 
from functools import partial, wraps 
import time 

import tornado.ioloop 
import tornado.web 


EXECUTOR = ThreadPoolExecutor(max_workers=4) 


def unblock(f): 

    @tornado.web.asynchronous 
    @wraps(f) 
    def wrapper(*args, **kwargs): 
     self = args[0] 

     def callback(future): 
      self.write(future.result()) 
      self.finish() 

     EXECUTOR.submit(
      partial(f, *args, **kwargs) 
     ).add_done_callback(
      lambda future: tornado.ioloop.IOLoop.instance().add_callback(
       partial(callback, future))) 

    return wrapper 


class MainHandler(tornado.web.RequestHandler): 

    def get(self): 
     self.write("Hello, world %s" % time.time()) 


class SleepHandler(tornado.web.RequestHandler): 

    @unblock 
    def get(self, n): 
     time.sleep(float(n)) 
     return "Awake! %s" % time.time() 


class SleepAsyncHandler(tornado.web.RequestHandler): 

    @tornado.web.asynchronous 
    def get(self, n): 

     def callback(future): 
      self.write(future.result()) 
      self.finish() 

     EXECUTOR.submit(
      partial(self.get_, n) 
     ).add_done_callback(
      lambda future: tornado.ioloop.IOLoop.instance().add_callback(
       partial(callback, future))) 

    def get_(self, n): 
     time.sleep(float(n)) 
     return "Awake! %s" % time.time() 


application = tornado.web.Application([ 
    (r"/", MainHandler), 
    (r"/sleep/(\d+)", SleepHandler), 
    (r"/sleep_async/(\d+)", SleepAsyncHandler), 
]) 


if __name__ == "__main__": 
    application.listen(8888) 
    tornado.ioloop.IOLoop.instance().start() 
+0

Ceci est une bonne réponse. – Glycerine

Questions connexes