Я пытаюсь написать обработчик запросов Tornado, который делает асинхронные HTTP-запросы и возвращает данные клиенту, когда он получает его от своих асинхронных запросов. К сожалению, я не могу заставить Tornado возвращать любые данные клиенту, пока все его Async HTTPRequests не будут завершены.Tornado потоковый HTTP-ответ как AsyncHTTPClient получает фрагменты
Демонстрация моего обработчика запросов ниже.
class StreamingHandler(web.RequestHandler): all_requested = False requests = [] @web.asynchronous def get(self): http_client = httpclient.AsyncHTTPClient() self.write('some opening') big_request = httpclient.HTTPRequest(url='[some_big_request]', streaming_callback=self.on_chunk) small_request = httpclient.HTTPRequest(url='[some_small_request]', streaming_callback=self.on_chunk) self.requests.append(http_client.fetch(big_request, callback=self.on_response_complete)) self.requests.append(http_client.fetch(small_request, callback=self.on_response_complete)) self.all_requested = True def on_chunk(self, chunk): self.write('some chunk') self.flush() def on_response_complete(self, response): if self.all_requested and all(request.done() for request in self.requests): self.write('some closing') self.finish()
Я бы ожидать запрос GET на этот обработчик сначала возвращает текст «некоторое открытие», а затем довольно быстро вернуться «некоторый кусок» для малого запроса, а позднее возвращение «некоторый кусок» (потенциально несколько раз) для большего запроса, прежде чем, наконец, верните «некоторое закрытие» и закрытие соединения. Вместо этого, после установления соединения, клиент ждет несколько секунд для завершения всех запросов, а затем сразу получает все HTTPResponse, перед закрытием.
Как я могу получить желаемое поведение от Tornado?
Заранее благодарен!
Привет, спасибо. Несколько вопросов: объясните, почему мой код не работает, а ваш? Кажется, что до некоторой мистической пользы «урожайности» с tornado.gen.coroutine. Как вы можете гарантировать, что после того, как вы представили список фьючерсов, чтобы запросы были полными, и безопасно писать «закрытие»? – majackson
@majackson: То, как Торнадо реализует сопрограммы. Используя 'yield', ваша функция становится генератором, поэтому вы можете эффективно запускать и останавливать ее в тех точках, где вы« выполняете »задачи. Когда вы выполняете задание (или список задач, которые Tornado выполняет сразу), вы сообщаете IOLoop Tornado, что он может «остановить» выполнение вашей функции и сделать другие вещи. Когда он «вернется» к вашей функции, он начнется там, где он остановился. Код вашей функции по-прежнему будет выполняться сверху вниз, но Tornado также перейдет к другим функциям. Это похоже на то, как это делает Node.js. – Blender