2016-10-31 2 views
0

Я хочу написать простой асинхронный HTTP-сервер с Tornado. Мне непонятно, как установить обратный вызов, чтобы освободить сервер для дополнительных запросов во время обработки текущего запроса.Простой асинхронный сервер с торнадо Python

Код я написал это:

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() 

Для проверки я попытался отправить несколько запросов POST параллельно:

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

В настоящее время сервер заблокирован во время perform_long_task() обрабатывается. Мне нужна помощь, чтобы сервер был неблокирующим.

+0

Я думаю, вы хотите ['gen.sleep'] (http://www.tornadoweb.org/en/stable/gen.html#tornado.gen.sleep) вместо' time.sleep' на своем пути к запись асинхронного кода –

+0

«Сон» - это просто отложить обработку запроса в этом примере. Я ожидаю, что этот окончательный код будет иметь процесс реального времени. – Yuval

+0

Прочитайте эту функциональную документацию. * это неблокирующий аналог time.sleep (который не должен использоваться в сопрограммах, поскольку он блокируется) * –

ответ

0

Никогда не принимайте time.sleep в коде Торнадо!

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

ли это в вашем коде вместо:

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() 

Вам не нужно называть self.finish - когда "пост" сопрограмма отделки, Tornado автоматически завершает запрос.

Вы должны предоставить self.perform_long_task(), в противном случае Tornado закончит ваш запрос раньше, чем вы назовете «self.write()».

После того, как вы внесете эти изменения, две команды «curl» покажут, что вы выполняете параллельную обработку в Tornado.

0
  1. Я по-прежнему использую time.sleep(), так как мой код вызывает другой код, который я не могу контролировать, как написано.
  2. FAQ http://www.tornadoweb.org/en/latest/faq.html#why-isn-t-this-example-with-time-sleep-running-in-parallel описывает три метода. Третий - это то, что мне нужно.

Единственное изменение мне нужно в коде заменить: выход self.perform_long_task (* арг ** json_input)
, который работает только для класса, который написан на асинхронном,

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

Все ответы и комментарии были полезными. Большое спасибо!

Смежные вопросы