Синхронная выборка в Tornado

В официальной документации Tornado (https://www.tornadoweb.org/en/stable/guide/async.html) есть пример синхронной выборки, но когда я помещаю его в метод get моего IndexHandler, он возвращает следующую ошибку:

  File "/home/stefan/.local/lib/python3.6/site-packages/tornado/web.py", line 1697, in _execute
    result = method(*self.path_args, **self.path_kwargs)
  File "ex1.py", line 19, in get
    client = tornado.httpclient.HTTPClient()
  File "/home/stefan/.local/lib/python3.6/site-packages/tornado/httpclient.py", line 107, in __init__
    self._async_client = self._io_loop.run_sync(make_client)
  File "/home/stefan/.local/lib/python3.6/site-packages/tornado/ioloop.py", line 526, in run_sync
    self.start()
  File "/home/stefan/.local/lib/python3.6/site-packages/tornado/platform/asyncio.py", line 148, in start
    self.asyncio_loop.run_forever()
  File "/usr/lib/python3.6/asyncio/base_events.py", line 428, in run_forever
    'Cannot run the event loop while another loop is running')
RuntimeError: Cannot run the event loop while another loop is running

Мой код выглядит так:

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.httpclient
from tornado.options import define, options

define("port", default=8000, help="run on the given port", type=int)

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        client = tornado.httpclient.HTTPClient()
        response = client.fetch('https://www.google.com')
        print(response.body)


if __name__ == "__main__":
    tornado.options.parse_command_line()
    app=tornado.web.Application(handlers=[(r"/", IndexHandler)],debug=True)
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

Я считаю, что мне следует внести изменения в main, чтобы заставить его работать.


person Laika_Boss    schedule 20.11.2019    source источник


Ответы (1)


Потому что, как вы можете видеть в вашей трассировке, «синхронный» fetch запускает свой собственный ioloop под капотом. Проще всего исправить def get как сопрограмму (либо как async def get, либо с помощью декоратора @gen.coroutine) и использовать асинхронную выборку.

class IndexHandler(tornado.web.RequestHandler):
    async def get(self):
        client = tornado.httpclient.HTTPClient()
        response = await client.fetch('https://www.google.com')
        print(response.body)
person Fine    schedule 22.11.2019
comment
Спасибо за ответ. Я сделал асинхронную версию, похожую на эту (разница только в том, что я использовал AsyncHTTPClient вместо вашей HTTPClient), но мне было интересно, можно ли сделать то же самое синхронно. - person Laika_Boss; 22.11.2019