https://greyli.com/flask-fastapi/
TLDR: FastAPI 是基于 Web 框架 Starlette 添加了 Web API 功能支持的(框架之上的)框架,而 Flask 是和 Starlette 同类的通用 Web 框架,两者不应该放到一起比较。
文中观点或有偏颇,欢迎指正和补充。
1
renmu123 2021-05-04 12:05:06 +08:00 via Android
1. 如果一个框架看着像 web 框架,用着像 web 框架,那是不是 web 框架?
2. 如果有一个基于 flask,pydatic 和 openapi 也开箱即用的框架(我不知道现在有没有出现,很久没写 flask 了,但如果有应该会有挺多人买单),那么它能不能和 flask 做比较吗?我个人觉得是可以的。 ps:某乎有不少这样的文章,大部分都是为他们的公众号引流的。 |
2
mekingname 2021-05-04 12:14:38 +08:00 2
我是《用它 5 分钟以后,我放弃用了四年的 Flask 》的作者。感谢博主的澄清。
其实我写这篇文章的用意,并不是对比两个框架谁好谁不好。我想表达的就是我用 FastAPI,用起来很爽很舒服。仅此而已。 就像博主举的例子,苹果和橙汁。确实,苹果和橙汁都不是同一类东西。但是,这不妨碍橙汁比苹果味道好,所以我喜欢喝橙汁,不喜欢吃苹果。我并不关心橙汁是基于什么做出来的,也不关心做橙汁的橙子与苹果谁好谁坏。我只关心最终拿给享用的东西,谁的味道好。 以后如果有一个框架基于 Flask,并且有比 FastAPI 更好的用户体验,那我也会毫不犹豫转过去的。 |
3
greyli OP @renmu123
> 1. 如果一个框架看着像 web 框架,用着像 web 框架,那是不是 web 框架? 这个问题我没理解。你可以说 Flask 和 FastAPI 都是 Web 框架,但是它们的性质是完全不同的。 > 2. 如果有一个基于 flask,pydatic 和 openapi 也开箱即用的框架(我不知道现在有没有出现,很久没写 flask 了,但如果有应该会有挺多人买单),那么它能不能和 flask 做比较吗?我个人觉得是可以的。 文中提到的 APIFlask 算一个(不过是基于 Marshmallow 而不是 Pydantic )。基于 Flask 的框架和 Flask 本身比较有什么意义呢?「骑着自行车的我」和「我」进行比较? |
4
greyli OP @mekingname 很抱歉把你的文章挑出来作为反面示例,希望没有冒犯到你。
苹果和橙汁可以比较,但这种比较是不合理不公正的(这是我想来澄清这件事的主要原因)。成年人和小孩子当然可以比武,但是这种比武不是建立在对等实力上的。我个人认为推介 FastAPI 更合理的行文方向有两种:单独介绍 FastAPI 的特性(不用和谁比较);介绍 Flask 搭配某些 REST API 扩展相对于 FastAPI 的劣势(公平合理)。 > 以后如果有一个框架基于 Flask,并且有比 FastAPI 更好的用户体验,那我也会毫不犹豫转过去的。 欢迎试试 APIFlask,不过它还是个新项目,或许用户体验并不优于 FastAPI 。 |
5
charlie21 2021-05-04 12:39:37 +08:00
|
6
joApioVVx4M4X6Rf 2021-05-04 12:41:48 +08:00
@greyli 你最近在用 python 吗?看了你的书入门的 web,结果发现现在 python 很多都是做内部系统了。
|
7
superrichman 2021-05-04 12:42:58 +08:00 via iPhone
我把 ae86 的引擎换成赛车的就不让我和你的原厂五菱宏光比赛了?
|
8
mekingname 2021-05-04 12:43:25 +08:00
@greyli 没问题,欢迎技术交流。
> 成年人和小孩子当然可以比武,但是这种比武不是建立在对等实力上的。 Flask 其实年龄比 Fastapi 更大吧。我们是不是能这样认为:Flask 是一个普通的成年人,Fastapi 是一个经过基因增强的变种小孩。我们发现这个小孩比成年人还厉害。这样对比似乎就合情合理了吧?变种小孩跟普通小孩对比,岂不是更不公平? > 我个人认为推介 FastAPI 更合理的行文方向有两种:单独介绍 FastAPI 的特性(不用和谁比较);介绍 Flask 搭配某些 REST API 扩展相对于 FastAPI 的劣势(公平合理)。 是的,这样介绍确实能更公平全面讲述 FastAPI 的特性。我以后的文章注意一下。 |
9
LeeReamond 2021-05-04 12:48:39 +08:00 via Android 6
有一说一,主题说的倒是没错,不过辨析的意义是什么呢,又一个 python 版的回字四种写法吗
|
10
greyli OP @mekingname 我只是打个比方说明这是一种不对等关系……
|
11
greyli OP |
12
renmu123 2021-05-04 13:06:23 +08:00 via Android
@greyli 我的意思多数最终用户(程序员)不会那么在意概念,能动的轮子就是好轮子。严格来说,我认为你说得肯定是没有问题的。
我们可不可以说“骑着自行车的我”比“我”就速度来说更快。用框架的功能来说就是,某个功能更加好用 |
13
greyli OP @v2exblog 做内部系统不也挺好,其他语言流行再学就是了。有一个语言 /框架作为基础再学其他语言 /框架也会容易得多。
|
14
LeeReamond 2021-05-04 13:31:04 +08:00 via Android
@greyli 不是很清楚开源项目的维护者本身如何产生利益相关,不过 io 复用为本身运行效率低下的 io 解决了大问题,本身大势所趋,fastapi 全是其中一个比较圆的轮子,且营销较好。我觉得你既然还在维护旧框架,本身是逆潮流而行,各方面不被理解也是正常的
|
15
greyli OP @LeeReamond 我指的是我作为维护者,不希望其他人用这种不合理的对比来让用户对 Flask 产生误解。我并不否认 FastAPI 各方面很优秀。
|
16
abersheeran 2021-05-04 14:01:46 +08:00
@LeeReamond 上了 greenlet 优化的 flask 不比 fastapi 慢。解决 IO 问题又不是只有 asyncio 可以用。
https://web-frameworks-benchmark.netlify.app/result?l=python |
17
abersheeran 2021-05-04 14:06:48 +08:00
说起来我司给我的最新任务是给他们写一个基于 bottle 的 template 。虽然我觉得上 asyncio 没什么成本(因为是一行代码都没有的新项目)但是大部分人在性能需求不高的时候还是更倾向于同步写法。
|
18
Sh1nes00n 2021-05-04 14:08:43 +08:00
我最初选用 fastapi 是因为路由写法`app.get()`和取参`def hello(param: int = 0)`,看到 flask2 即将支持这种路由感到非常欣慰。
还有尬吹性能的,还是那句话,没多少项目能活到拼性能那天,真到那天了,资本会给你最好的解决方案。 「在每个 commit 信息里都加上 emoji 并不可爱」 我看到这种操作方式后,在自己的 private repo 里也尝试了下,提交几个 commit 后发现,除了 feature 里增加🎉让我感到快乐外,普通 commit 添加表情(像😘)感觉太傻 x 了 |
19
wdhwg001 2021-05-04 14:17:47 +08:00
FastAPI/Starlette 实际用起来确实有不如 Flask 方便的地方,比如必须显式传递上下文,并且没有足够的生命周期管理。并且用它开发的时候,经常需要读两个文档和翻两份源码,而且 FastAPI 还经常导入 Starlette 的内容之后什么都不做,或者重写一份 Starlette 里已有的文档,这使得溯源过程变得更艰难了。
但说实话,我还是看好 asyncio 的未来的,无栈协程的性能问题其实应该怪 Python,而不是怪框架。 |
20
LeeReamond 2021-05-04 14:19:08 +08:00 via Android
@abersheeran 手机打字有些问题,我那句话本来想打的是 io 复用对于本身运行效率低的 python 意义重大,打错字了手机没发现,意思变得很奇怪。我觉得跑分这个事吧,毕竟 io 的大头还是在系统调用,跑分有不同结果也正常,但毕竟单线程下 io 复用在工业界广泛应用是大家用脚投票投出来的。
flask 本身是个很优雅的框架,那它也就要承受优雅的反作用,你只能无奈说现在大家不是很接受这个 |
21
Kobayashi 2021-05-04 14:25:43 +08:00 via Android
@abersheeran 这个 benchmark 没任何意义。视图函数是空的,匹配到直接返回空字符串,和实际完全脱钩,最起码得带一次数据库请求吧。
还是 tech empower benchmark 吧,测试指标更多,从不同方面比较。tech empower 里的 plaintext 指标应该对应你发的这个框架比较。 https://www.techempower.com/benchmarks/ https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview |
22
Kobayashi 2021-05-04 14:30:16 +08:00 via Android
@wdhwg001 Quart 倒是完全兼容了 Flask,有足够的钩子,还引入了上下文。不过好像性能与其他 Python 异步框架比还是差了点。
不过 FastAPI 只能算是一个个人项目,项目维护值得怀疑。PR 有 280+没有处理…… |
23
Richard14 2021-05-04 14:45:33 +08:00 1
@wdhwg001 我觉得主要原因还是对程序员心智负担的降低,在同样场景下,线程访问共享资源是需要锁的,而 python 的锁偏偏很重,难以优化,threadlocal 同理,这两点在 aio 中被有效解决。
|
24
abersheeran 2021-05-04 14:51:36 +08:00
@Kobayashi 微框架都是用社区的 ORM,这玩意我觉得加不加都行。如果是和 Django 比,那确实要带上数据库查询才比较公平。
@LeeReamond 我只觉得总有人把线程模型和协程模型的框架放一起比较性能,很有倾向性。不公正。 而且最近 pydantic 作者拉上 fastapi 一起裹挟群众强行把一个 pep 退回去了,总感觉有些飘了。 |
25
Kobayashi 2021-05-04 15:26:53 +08:00
@abersheeran 问题不是我们没有比较哪个 ORM 更快,而是没有顾忌数据库请求甚至其他因素对于整个请求的影响。
尽管 HTTP 请求和数据库查询都可以异步,但引入对数据库查询的考虑,势必也会对最终数据有影响。我从公司门口走到工位需要 10 秒,你花了 20 秒,但考虑到我们两个坐电梯上楼的事件,也不能说其中一人比另一人快 2 倍吧。 Andrew Godwin 在 19 年 AU Pycon 上也提出过类似的说法, > most of the program i write tend to spend at least 2/3 of time waiting for database and they can't do anything. (当然这是本地、或集群内部的情况,也没人想不开跨区域使用数据库吧) 从测试代码与实际请求的贴合程度考虑,只考虑数据库请求可能也不够,这也是大多数人觉得 benchmark 没有意义的主要原因。但数据库请求的确是大多数接口最常做的事情。 而我们这里只是一个字符串空响应的 benchmark,实在是过于简陋、与实际偏离太远了。 |
26
greyli OP @Kobayashi 性能不清楚,补充一点关于 Quart 的额外信息:从 Flask 2.0 开始,Quart 会是官方推荐的 Async Flask 替代选项。Flask 2.0 支持的 async/await 是一个折中方案(基于 asgiref 做的 WSGI->ASGI 转换),如果想要完全基于 ASGI 的异步实现那么可以选择 Quart (和 Flask API 基本保持一致)。前段时间也在讨论把 Quart 加入到 Pallets 组织作为官方项目维护(暂时还没有定具体时间,可以先看作小道消息)。
|
27
abersheeran 2021-05-04 15:37:56 +08:00
@Kobayashi 我倒是觉得做这个 benchmark 就够了。能体现框架本身的代码运行速度如何,屏蔽掉其他的因素。
实际业务里干扰很多的。比如来个 N+1 查询,哪怕这框架优化到特定平台指令集上级别都没有什么用。再比如说 asyncio 的框架其实在业务里都有一个缺点,就是大部分程序员都没办判断出自己是不是在异步框架里跑了同步耗时操作,所以往往上了异步反而没有同步的框架快。 benchmark 说到底就是个能用于营销的本钱。“最快的框架”,多唬人啊。 |
28
abersheeran 2021-05-04 15:40:58 +08:00
@greyli Flask2.0 的异步支持是用第三方中间件把 WSGI 转 ASGI ???
|
29
greyli OP @abersheeran 目前是这样实现的( https://github.com/pallets/flask/pull/3412 ),当然这只是第一步,完全的 ASGI 支持会在 Werkzeug 实现( https://github.com/pallets/werkzeug/issues/1322 ),不过不确定哪天能实现。
|
30
abersheeran 2021-05-04 16:05:41 +08:00
@greyli 看了看这个 issue 的讨论,感觉我好像抢在 werkzeug 之前把支持双协议的 framework/toolkit 做完了 https://github.com/abersheeran/baize 。hhh 有时候个人开发的好处就是有想法可以直接干完,社区就需要讨论讨论。
|
31
greyli OP @abersheeran 哈哈,是的。我上个月提议加 app.get 、app.route 、app.delete 这些装饰器一开始是被拒绝的,后来另一个成员创建了一个 PR 经过二次讨论后才最终合并(被拒绝后我就把正在开发的 APIFlask 从扩展改成了继承 Flask 基类的框架,然后加了这些装饰器)。
|
33
abersheeran 2021-05-04 16:40:19 +08:00
@greyli hhh 被拒之后自己重开,我老这么干。
|
34
johnsona 2021-05-04 19:08:19 +08:00 via iPhone
@mekingname 好家伙 v 站卧虎藏龙 居然把文章作者炸出来
|
35
encro 2021-05-04 23:03:44 +08:00 4
首先感谢作者对开源的贡献,
然而比较无法回避, 避免被比较的唯一办法就是胜出。 |