Flask 的替代品 aiohttp 和 Quart

本来只是为了研究一下 Flask  怎么去支持早已在 Python 的支持的 coroutine 功能,没想步子越迈越大,直顶到 aiohttp Web 服务器和 Flask  的异步实现版本 Quart。Flask 得费了好一番功夫去获得 EventLoop,可知 aiohttp 和 Quart 的路由方法直接就允许 async 的,那个 EventLoop 自然就在其中。从 async 的路由方法出发去调用别的异步方法就是一件十分轻松的事情。

下面来稍稍体验一下用分别用  aiohttp 和 Quart 实现简单的异步服务器,我们的关注点在它的异步路由。

异步的  aiohttp Web 服务器

aiohttp 除了 HTTP 客户端功能,还有服务端端,因它的异步特性,可以用它建立一个异步的 Web 服务器,也就是它的路由方法也是异步的,完全可用它来替代 Flask 本身。

pip install aiohttp 安装

下面是一个简单的例子

由于 hello() 方法加了 async 关键字,可直接由路由 / 关联来执行,所以它是有一个 EventLoop 在里头的,加了一行代码在控制台打印出该 EventLoop。同是我们也来观察一下它用什么线程来处理客户端请求。aiohttp 服务启动的默认端口号是 8080

======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)

发出请求

$ curl http://localhost:8080/
{"event_loop": "<_UnixSelectorEventLoop running=True closed=False debug=False>", "thread": "MainThread"}

比起 Flask 应用 coroutine 时不需要显式的用  asyncio.run() 或用下面几行代码

不过 aiohttp 的服务总是用主线程去处理客户端请求,那就是说使用 aiohttp 做服务器的话,需要各个层所有的方法都是 async 的,这样多个请求之前才不至于互相阻塞。同时 aiohttpapp.add_routes() 注册路由时,只能支持 async 修饰的方法,也就是说 asiohttp 不支持非异步的方法。这要求后端的所有实现方法必须小心,一旦调用了非异步方法将阻塞其他的请求。

Flask 的超集版本 Quart

Quart 直接被定义为 Flask 的超集,支持异步路由,使用了 Flask 的 API,支持 Flask 的扩展,还添加了一些 Flask 不具备的功能。Quart 当前版本 0.13.0,它从 0.7.0 开始需要 Python 3.7.0 或更高版本的。

pip install quart 安装

下面来看熟悉的味道,同样测试 async 和 非 async 两个路由方法

python app.py 启动它,同样是监听在 5000 号端口

Running on http://127.0.0.1:5000 (CTRL + C to quit)
[2020-07-13 11:26:01,137] Running on 127.0.0.1:5000 over http (CTRL + C to quit)

访问及结果

$ curl http://localhost:5000/async
{
  "event_loop": "<_UnixSelectorEventLoop running=True closed=False debug=True>",
  "thread": "MainThread"
}
$ curl http://localhost:5000/sync
{
  "event_loop": "None",
  "thread": "ThreadPoolExecutor-0_0"
}

同样,既然是路由方法上可用 async 关键字,自然它在执行时能拿到当前的  EventLoop,调用其他的 async 方法不在话下。与 aiohttp 一样,async 的路由方法总是由主线程来处理请求。非 async  的路由方法由线程池来处理,这比 Flask 每请求创建一个新的线程要先进一些。

Quart 同时支持异步和非异步的方法,这给了我们更多的灵活性,比如使用非 async 路由方法时,某些地方我们可以手动的用 EventLoop 来调度,而不一定要求一切 async。

轻松搞上 websocket

Flask 支持 websocket 需要安装一个 flask-socketio 扩展,而 Quart 更简单,有装饰器支持

值得一试

一个获得 EventLoop 的工具方法

对于 Quart 中异步或同步路由中都想获得 EventLoop 进行更精细的方法调度,可以用下面的工具方法来获得或创建一个新的 EventLoop

线程上存在直接返回,否则创建一个 EventLoop, 如果是同步路由方法,必须自己用 event_loop.run_until_complete(...) 发起协程的执行,相当于进行 Promise 的最终兑现。

总结一下:

  1. aiohttp 只支持 async 路由方法,所有请求都在主线程中处理,任何非异步方法的调用都将阻塞其他的请求
  2. Quart 同时支持 async 和非 async 路由方法,async 路由由主线程处理,这一点与 aiohttp 的路由是一样的。
  3. Quart 的非 async 路由方法由线程池处理,比 Flask 每次请求新建线程要好
  4. Quart 允许我们同时用非 async 路由与 EventLoop 来控制
  5. 在 aiohttp 或 Quart 中使用 async 路由时反而要倍加小心,最好是所有方法都是 async

本文链接 https://yanbin.blog/flask-replacement-aiohttp-quart/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments