将龙卷风与 aiohttp(或其他基于异步的库)一起使用

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

我想将 tornado 与 aiohttp 和本机 python 3.5 协程等异步库一起使用,最新的 tornado 版本 (4.3) 似乎支持它。但是,当在龙卷风事件循环中使用它时,请求处理程序会无限期挂起。当不使用 aiohttp 时(即没有下面的 r = await aiohttp.get('http://google.com/')text = await r.text() 行),请求处理程序将照常进行。

我的测试代码如下:

from tornado.ioloop import IOLoop
import tornado.web
import tornado.httpserver
import aiohttp

IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')


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__":
    app = tornado.web.Application([
        (r"/", MainHandler),
    ])
    server = tornado.httpserver.HTTPServer(app)
    server.bind(8888, '127.0.0.1')
    server.start()
    IOLoop.current().start()

根据 docs,您的做法几乎是正确的。你必须 create/init Tornado 的 ioloop 和相应的 asyncio,因为 aiohttp 在 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()

你的代码卡住的原因是asyncio的ioloop实际上不是运行,只有Tornado的,所以await无限期地等待。

从 Tornado 5 开始,它的大部分异步函数 类 和装饰器,包括 IOLoop,不仅 兼容 与 Python 的标准 asyncio,但是当 Python 上的 Python 3.5+ 时 别名 .

这意味着当您使用 Tornado 的 IOLoop()@gen.coroutine 之类的东西时,Tornado 在幕后使用等效函数和 asyncio 中的 类。

这样您就可以使用 IOLoop.current().start() 并获得 asyncio 的 ioloop。