Using tornado with aiohttp (or other asyncio-based libraries)

According to docs, you are doing it almost right. You have to create/init Tornado's ioloop with corresponding asyncio, since aiohttp is running on asyncio.

from tornado.ioloop import IOLoop
import tornado.web
import tornado.httpserver
import aiohttp
from tornado.platform.asyncio import AsyncIOMainLoop
import asyncio

class MainHandler(tornado.web.RequestHandler):
    async def get(self):
        r = await aiohttp.get('http://google.com/')
        text = await r.text()
        self.write("Hello, world, text is: {}".format(text))

if __name__ == "__main__":
    AsyncIOMainLoop().install()
    app = tornado.web.Application([
        (r"/", MainHandler),
    ])
    server = tornado.httpserver.HTTPServer(app)
    server.bind(1234, '127.0.0.1')
    server.start()
    asyncio.get_event_loop().run_forever()

The reason why your code get stuck, is that asyncio's ioloop actually is not running, only the Tornado's one, so await is waiting indefinitely.


Starting from Tornado 5, most of its async functions, classes and decorators, including IOLoop, are not only compatible with Python's standard asyncio, but are aliases to its counterparts when running on Python 3.5+.

That means when you use Tornado's things like IOLoop(), @gen.coroutine and such, behind the scenes Tornado uses the equivalent functions and classes in asyncio.

This way you can use IOLoop.current().start() and you'll get asyncio's ioloop.