简体   繁体   中英

Simple async server with tornado Python

I want to write a simple async http server with Tornado. It is not clear to me how to set the callback in order to free the server for additional requests while the current request is processed.

The code I wrote is:

import tornado.web
from tornado.ioloop import IOLoop
from tornado import gen
import time

class TestHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def post(self, *args, **kwargs):
        json_input = tornado.escape.json_decode(self.request.body)
        print ('Now in POST. body: {}'.format(json_input))
        self.perform_long_task(*args, **json_input)

    @gen.coroutine
    def perform_long_task(self, **params):
        time.sleep(10)
        self.write(str(params))
        self.finish()

application = tornado.web.Application([
    (r"/test", TestHandler),
    ])

application.listen(9999)
IOLoop.instance().start()

To test I tried to send few POST requests in parallel:

curl -v http://localhost:9999/test -X POST -H "Content-Type:appication/json" -d '{"key1": "val1", "key2": "val2"}' &

Currently the server is blocked while perform_long_task() is processed. I need help getting the server to be a non-blocking.

Never use time.sleep in Tornado code!

http://www.tornadoweb.org/en/latest/faq.html#why-isn-t-this-example-with-time-sleep-running-in-parallel

Do this in your code instead:

class TestHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def post(self, *args, **kwargs):
        json_input = tornado.escape.json_decode(self.request.body)
        print ('Now in POST. body: {}'.format(json_input))
        # NOTE: yield here
        yield self.perform_long_task(*args, **json_input)

    @gen.coroutine
    def perform_long_task(self, **params):
        yield gen.sleep(10)
        self.write(str(params))
        # NOTE: no need for self.finish()

You don't need to call self.finish - when the "post" coroutine finishes, Tornado automatically finishes the request.

You must yield self.perform_long_task(), though, otherwise Tornado will end your request early, before you've called "self.write()".

Once you make these changes, two "curl" commands will show that you're doing concurrent processing in Tornado.

  1. I'm still using time.sleep() as my code calls other code that I can't control how is written.
  2. The FAQ http://www.tornadoweb.org/en/latest/faq.html#why-isn-t-this-example-with-time-sleep-running-in-parallel describes three methods. The third one is what I needed.

The only change I needed in my code is to replace: yield self.perform_long_task(*args, **json_input)
which works only for a class that is written for async,

with: yield executor.submit(self.perform_long_task,*args, **json_input)

All replies and comments were helpful. Many thanks!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM