Using a simple python generator as a co-routine in a Tornado async handler?

后端 未结 2 1938
梦谈多话
梦谈多话 2020-12-08 03:19

I have a python generator function which yields chunks of text. I would like to write a get method for a tornado.web.RequestHandler subclass that w

相关标签:
2条回答
  • 2020-12-08 03:48

    Here's a basic version of what you are describing. To avoid blocking you can pass your generator to the IOLoop via a callback function. The trick here is since you are not using a process that does actual IO and so has no os level process/file handler to add to the IOLoop via add_handler, you can instead use a simple add_callback call and call it repeatedly from within the callback function to keep the function in the IOLoop callback queue until the generator has finished.

    import tornado.httpserver
    import tornado.ioloop
    import tornado.web
    
    class TextHandler(tornado.web.RequestHandler):
        @tornado.web.asynchronous
        def get(self):
            self.generator = self.generate_text(1000)
            tornado.ioloop.IOLoop.instance().add_callback(self.loop)
    
        def loop(self):
            try:
                text = self.generator.next()
                self.write(text)
                tornado.ioloop.IOLoop.instance().add_callback(self.loop)
            except StopIteration:
                self.finish()
    
        def generate_text(self, n):
            for x in xrange(n):
                if not x % 15:
                    yield "FizzBuzz\n"
                elif not x % 5:
                    yield "Buzz\n"
                elif not x % 3:
                    yield "Fizz\n"
                else:
                    yield "%s\n" % x
    
    application = tornado.web.Application([
        (r"/text/", TextHandler),
    ])
    
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
    
    0 讨论(0)
  • 2020-12-08 04:02

    It is also possible to use the new tornado's gen interface to async processes:

    import tornado.httpserver
    import tornado.ioloop
    import tornado.web
    import tornado.gen
    
    class TextHandler(tornado.web.RequestHandler):
    
        @tornado.web.asynchronous
        @tornado.gen.engine
        def get(self):
    
            def cb(it, callback):
                try:
                    value = it.next()
                except StopIteration:
                    value = None
                callback(value)
    
            it = self.generate_text(1000)
            while True:
                response = yield tornado.gen.Task(cb, it)
                if response:
                    self.write(response)
                else:
                    break
            self.finish()
    
        def generate_text(self, n):
            for x in xrange(n):
                if not x % 15:
                    yield "FizzBuzz\n"
                elif not x % 5:
                    yield "Buzz\n"
                elif not x % 3:
                    yield "Fizz\n"
                else:
                    yield "%s\n" % x
    
    application = tornado.web.Application([
        (r"/text/", TextHandler),
    ])
    
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
    
    0 讨论(0)
提交回复
热议问题