Торнадо некорректно дает фьючерсы

Мне нужно асинхронно сделать несколько HTTP-вызовов внутри обработчика запросов торнадо.

попытка вернуть фьючерсы плохо документирована и практически невозможна на собранном asyncio.gather на уровне обработчика торнадо.

Я пробовал aiohttp, который отлично работает сам по себе, однако, помещая его в обработчик торнадо, он вызывает цикл, который уже используется. Если вы можете показать мне, как ввести в IOLoop несколько новых вариантов будущего решения, это было бы неплохо.

Я также пробовал использовать tornados AsyncHTTPClient, который вопреки документации фактически не использует yield, но возвращает ответ, когда вы используете await.

Есть ли по этому поводу свежая документация? ВСЕ пример не работает для нескольких асинхронных запросов.

согласно этой документации http://www.tornadoweb.org/en/stable/gen.html#module-tornado.gen

@gen.coroutine
def get(self):
    http_client = AsyncHTTPClient()
     response1, response2 = yield [http_client.fetch(url1),
                              http_client.fetch(url2)]
    response_dict = yield dict(response3=http_client.fetch(url3),
                           response4=http_client.fetch(url4))
    response3 = response_dict['response3']
    response4 = response_dict['response4']

однако при попытке сделать это сам yield выдает ошибку, и замена этого на await дает результат. однако вы не можете ждать объекта dict, например yield. Как я могу это обойти?

Python 3.6.7 Торнадо 5.1.1 Aiohttp 3.5.4


person Erik K    schedule 31.01.2019    source источник
comment
Как вы запускаете эту сопрограмму?   -  person yorodm    schedule 31.01.2019
comment
Если вы хотите отправлять несколько HTTP-запросов асинхронно, используйте _1 _ . Это позволяет получать фьючерсы из списка. Некоторое время назад я ответил на аналогичный вопрос: stackoverflow.com/a/54125927/1925257   -  person xyres    schedule 31.01.2019
comment
@xyres, почему тогда документация, связанная с торнадо, неверна? он ясно показывает получение нескольких фьючерсов из списка. сбивает с толку. Кроме того, это плохая маска для того, что я сказал выше. вы можете создать свой собственный список фьючерсов, а затем await их вместо уступки или чрезмерно усложненного WaitIterator, как это пытаются вам сказать плохо сделанные документы торнадо.   -  person Erik K    schedule 01.02.2019
comment
@xyres, чтобы добавить к этому WaitIterator по-прежнему выдает ошибку "AssertionError: yield from wasn't used with future\n" Есть что-то, что изначально нарушено во взаимодействии tornados со сломанным asyncio   -  person Erik K    schedule 01.02.2019
comment
@ErikK Прежде всего, успокойся. Во-вторых, WaitIterator позволяет получать / ожидать фьючерсы асинхронно, что означает, что он дает вам результат будущего по мере их разрешения. Если вы просто уступите / ожидаете список фьючерсов, вы не получите результат, когда фьючерс разрешится. Вы получите результат только тогда, когда будут разрешены все фьючерсы.   -  person xyres    schedule 01.02.2019
comment
@ErikK Кроме того, пожалуйста, не заходите сюда, все оружие пылает, называя хорошо обслуживаемые библиотеки сломанными, потому что вам трудно научиться их использовать. Удачи в поисках помощи с таким отношением.   -  person xyres    schedule 01.02.2019
comment
@xyres, давайте начнем с вашего аналогичного ответа. вы показываете, что он работает вне обработчика торнадо, используя asyncio. tornado теперь делает вид, что использует asyncio под капотом. если вы попытаетесь уступить, находясь в обработчике, он сломается. если вы попробуете WaitIterator в обработчике, он сломается. если вы попытаетесь вызвать текущий цикл событий, находясь в обработчике, он прервется. Хотелось бы увидеть, как ваш пример работает в обработчике. его довольно просто использовать в узле.   -  person Erik K    schedule 01.02.2019


Ответы (1)


В ваших комментариях используется слово await, поэтому похоже, что вы столкнулись с различием между собственными сопрограммами (определенными с помощью async def и await) и декорированными сопрограммами (определенными с помощью @gen.coroutine и yield). Вы можете использовать только yield списки и словари непосредственно в декорированных сопрограммах.

В собственной сопрограмме вы должны использовать tornado.gen.multi (или asyncio.gather):

async def get(self):
    http_client = AsyncHTTPClient()
    response1, response2 = await gen.multi([http_client.fetch(url1),
                                            http_client.fetch(url2)])
    response_dict = await gen.multi(dict(response3=http_client.fetch(url3),
                                         response4=http_client.fetch(url4)))
    response3 = response_dict['response3']
    response4 = response_dict['response4']

Различия между двумя стилями сопрограмм задокументированы здесь

person Ben Darnell    schedule 02.02.2019
comment
Спасибо за это. Должно быть, я где-то пропустил крошечный бит, который делает различие между собственной асинхронной сопрограммой и сопрограммой tornados. У меня уже есть asyncio.gather, работающий вне обработчиков торнадо для мульти-фьючерсов. Однако при подключении к торнадо я попадал в цикл, который уже выполнял ошибки или выдавал ошибки. Я думаю, что в вашем ответе есть ответы, которые мне нужны, хотя спасибо - person Erik K; 03.02.2019