Skip to content

Commit

Permalink
Add public/assets/images/flask-is-dead-you-should-use-fastapi.png
Browse files Browse the repository at this point in the history
  • Loading branch information
169 committed Dec 18, 2023
1 parent f71ee96 commit 2ef1bf8
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
155 changes: 155 additions & 0 deletions src/pages/posts/flask-is-dead-you-should-use-fastapi.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
layout: '@/templates/BasePost.astro'
title: Flask已死,FastAPI是未来
description: Flask已死,FastAPI才是未来
pubDate: 2023-12-18T12:00:00Z
imgSrc: '/assets/images/flask-is-dead-you-should-use-fastapi.png'
imgAlt: 'Use FastAPI'
---

周末搜索一些信息时发现2023年还有不少人推荐使用Flask作为Python的Web框架,而我已经认为「Flask已死,[FastAPI](https://github.com/tiangolo/fastapi)是未来」,所以写下本文,欢迎讨论和反驳。

### Flask vs FastAPI

Flask是一个在Python开发者心目中十分重要的项目,如果你是一个Web开发者,我相信你一定用过Flask,但是可能没有用过FastAPI。这个和国外相比可能会更明显一点,我觉得主要是因为国内已经没有多少人在写技术文章推荐,教大家分辨趋势或者主流,而一些老手即便知道它们的优缺点可能也懒得写对比文章,结果造成很多新人不了解怎么选,只能看一些老的文章、大V或者书籍的推荐作为选择的依据。

但是如果你有兴趣,你可以考证2点:

1. 最近1-2年,Python相关的知名新项目中只要有Web的,基本都使用FastAPI。
2. 今天(2023年12月18日)在Github上,FastAPI的star数(66k)已经超过了Flask(65.2)。

接着看一下Python官方的开发者调查中Web框架占比的变化:

[](https://github.com/langchain-ai/langchain/assets/10000925/1c523199-11ec-40dc-af98-c3273abed51d)

可以看到19年FastAPI甚至不是一个选项,而22年已经占到25%的比率。这个开发者调查需要年中才会统计出上一年的,所以2023年的得明天第三季度才能知道,我预计FastAPI可以达到35%左右。

需要注意这个占比数据包含了现有系统,所以Django和Flask不容易跌得很快,但是趋势是很明显的。

我们知道Web框架这个领域是很高产的,基本每年都有新的框架诞生,大部分框架昙花一现,但有的框架却能够长青。FastAPI诞生于2018年底,在2019年年底左右开始崭露头角,那么为什么它可以在短短的5年里让关注度超过在2010年底诞生的Flask呢?接着我们顺着时间线捋捋Python Web框架和相关解决方案的发展来理解吧。

### Web框架(插件、工具)发展史

FastAPI作者是一个非常关注Python生态发展的开发者,延伸阅读链接2是一篇作者写的<Alternatives, Inspiration and Comparisons>,详细的介绍了FastAPI出各个库中的借鉴或者启发的细节,而发展史这部分我也参考了这篇文章。大家应该看看原文,里面包含了为什么会出现FastAPI以及作者的一些设计哲学。
#### Django

Django是Python社区里最早做到统治级别的Web框架,当时知名的Instagram就是用它构建的。它的特点是大而全,各种web开发需要用到的细节它基本都有相关的模块,尤其和关系数据库、管理功能等方面耦合度非常高。对于熟悉的老手,这是一个生产级别的框架,但即便有完整的文档,对于初学者非常不友好,学习曲线中后期很陡峭,它的复杂度和定制成本非常高。

其实我这篇文章,也可以叫做「Django和Flask之死」,但是在框架应用场景角度来说Flask和FastAPI对比更合适,而Django直接和FastAPI相比有一些差别。在一些商业场景(例如CMS)Django依然是首选,而Flask(甚至FastAPI)看起来更像个「玩具」,所以Django短时间不会被取代(Flask这些年不是也是没取代的了嘛)。

#### Django REST Framework(DRF)

Django主旨是为了在后端生成 HTML,而不是创建现代前端(如 React、Vue.js )或与其通信的其他系统使用的 API。所以FastAPI其实和Django REST Framework直接对标,它们主要场景都是构建 Web API,但是名字上也可以看出来,DRF还是依托于Django框架,所以缺点一样。

#### Flask

Flask是一个「微」框架(Micro framework),和Django截然相反,它仅保留小部分的核心,还为了解耦把功能拆分成几个库(如Jinja2,Werkzeug等),所以开发者有足够的自由,你可以很容易写出相关功能的第三方插件。它里面的蓝图、上下文、装饰器表示路由、信号等等设计在当时是非常先进的,再加上文档写的很完整,可以说对新手极为友好。

#### Flask REST Frameworks

由于Flask的简单性,它非常适合构建API,不过由于Flask什么也不带,我们需要专门的REST框架。所以相继出现了 flask-restful 、Flask-RESTPlus、flask-api等框架,另外在Rest服务中,会需要数据验证、解析和规范等需要,也出现了Marshmallow、Webargs和APISpec,一直到Flask-apispec。但是整个发展过程中没有出现一个足够好的能够对标DRF的Flask REST Framework。

而到这个阶段,Flask的缺点其实也暴露了。

Flask本来的优点是灵活性和极简主义,但这意味着很多很多组件需要自己造,这个要不然需要公司够大专门有开发者开发和维护,要不然得个人能力极强,否则插件很难达到生产级别,这就造成Flask的第三方插件质量层次不齐,且无法保证长期维护。就像我上面说的那些库,现在来看,其中已经很多不再维护了。

所以即便是今天,你想用Flask构建一个API服务,还是要东拼西凑各个组件,其中某些组件有些没及时更新的地方要自己动手解决,这对于老手来说还好,对于新人来说很痛苦,尤其是你想要应用现在最新的实践方案和理念,只能望而兴叹。

#### Asyncio生态

从Python3.5开始,asyncio已经是未来的趋势了。所以开始出现了一些原生支持asyncio的Web框架,如aiohttp、Starlette和sanic。

这个时候Flask并不想接受改变,社区迟迟的不加入aio的支持,另外Flask原作者也去写rust了,把项目交给了2个维护者(现在只剩一个人了)。

而用于构架API服务的项目例如apistar,molten。它们都给FastAPI的带来了设计灵感。

#### FastAPI

接着就是诞生FastAPI了。作者本来也是想找到一个好的解决方案,但是以上种种都是自己的问题或者说局限性,所以作者就造了这个轮子。

### FastAPI为什么能成为统治者

这篇文章的核心部分啦,这些理由也是为什么FastAPI会替代Flask的原因。
#### 异步设计

在Flask的那个时代,代码执行是单线程、同步的,这意味着要依次处理请求,前一个请求完成前,其他请求消耗在等待 I/O 操作上。而asyncio是最好的解决方案,它让I/O成为异步操作,无需等待任务完成即可获取任务结果并继续处理其他任务请求。

而FastAPI天生支持并发和异步代码,代码写对了就可以在效率上达到极致,所以它被认为是目前最快的Python框架,效率和NodeJS或Go接近。当速度和性能至关重要时,FastAPI 是最佳选择。

#### 使用Pydantic做用户数据验证

API开发中数据格式的验证、解析和序列化是很常用的,在这些年的发展过程中出了很多种方案,而目前最好的方案就是[Pydantic](https://docs.pydantic.dev/latest/):

```
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
```

这个代码初看是ORM/dataclass的写法,其实是基于Python原生的Type Hints的语法给字段做类型注解,例如上例的`/items/`请求中的Item的schema已经定义好了,各个字段的值类型非常明确。和过去用schema描述甚至硬代码的方式相比很干净很pythonic,对于IDE支持也更好。

在现阶段,Pydantic在用户数据验证等领域是统治级别的,而FastAPI内置了它,这可以大大简化了验证过程,它还可以减少错误,所以FastAPI官网介绍优点中就提到这个方案可以将开发人员错误减少高达 40%。对于Python这种动态语言来说,如果不是用mypy强制类型检查,应用Pydantic是非常有必要的。

另外由于集成了Pydantic,所以非常容易在项目中添加ORM(如[SQLAlchemy](https://www.sqlalchemy.org/)),从请求中获得的对象可以直接传递到数据库,因为已经做过数据验证。反之亦然,可以将从数据库获取的对象直接返回。

相对的,Flask这方面的缺失的。

#### 原生支持ASGI

先提一下WSGI,他的全称是「Python Web Server Gateway Interface」,具体可以看延伸阅读链接三的《PEP 3333》,它是专门为 Web 应用程序和服务器相互交互而编写的 Python 标准。如果你使用过PHP或 Ruby 的人会更容易理解它。Flask的依赖Werkzeug就是WSGI套件,所以Flask支持的是这个老的WSGI,不支持ASGI。

WSGI的问题是无法利用异步达到性能和效率提升,所以Django组织首先提出了ASGI。它的全称是「Asynchronous Server Gateway Interface」,它是一个迭代但基本的重新设计,它提供了异步服务器/应用程序接口,并支持 HTTP、HTTP/2 和 WebSocket。与 WSGI 不同,ASGI 允许每个应用程序有多个异步事件。另外,ASGI 支持同步和异步应用程序。你可以将旧的同步WSGI Web应用程序迁移到 ASGI,也可以使用ASGI构建新的异步 Web 应用程序。

出结论之前,先稍微补充5个名词解释:

1. ASGI工具集。实现了ASGI相关功能(例如URL路由、Request/Response对象、模板引擎等)的库,在本文中主要指[Starlette](https://github.com/encode/starlette),它对标的是Flask的依赖Werkzeug。
2. ASGI Web框架。实现了ASGI规范的Web框架(例如FastAPI),而Flask、Django是实现了WSGI的Web框架,它是面向开发者编写应用程序,接口非常易用,开发者按照需求填业务逻辑就行。早期的框架都是内部实现了ASGI工具集,而后来的框架通常是组合合适的工具集来用,例如Flask用Werkzeug(自己家的),FastAPI用Starlette(别家的)。
3. Web应用。使用了Web框架创建的应用程序就是一个Web应用,而通常Web框架自带一个测试服务器,可以启动起来用于开发调试,如果不考虑性能和稳定性,你已经可以在浏览器里访问开发地址访问这个应用了。
4. Web服务器(Web Server)。现实世界要比预想的复杂,Web应用部署到生产环境后需要考虑请求负载均衡、服务静态文件、访问控制、反向代理等等需求,同时对于性能也很有要求,Web框架内置的Web服务器时远远达不到这个要求的,所以就需要有专门的Web服务器,现在主流的就是Nginx。
5. ASGI服务器。ASGI服务器是Web服务器和Web应用之间的桥梁,ASGI服务器也会遵守ASGI的规范,但是它的主要任务是满足转发请求的性能要求,所以主要做的是ASGI里面的G这部分,也就是网关,它的代码对于开发者写Web应用并不友好,不会有开发者直接使用ASGI写业务和路由逻辑。目前最知名的ASGI服务器是[Uvicorn](https://www.uvicorn.org/),另外使用本来是WSGI服务器的Gunicorn的`uvicorn.workers.UvicornWorker`也可以。都是生产环境推荐的用法。

过去一般WSGI的生产环境方案是 `Nginx+Gunicorn+Flask(Django)`,而现在ASGI的生产环境方案是 `Nginx+Uvicorn+FastAPI`

再补充一点。FastAPI无论看项目名字还是介绍都能感觉出来它是用于构建API服务的,事实上FastAPI自己的核心代码也确实是这样的,可以说它不是一个传统的、完全自己实现的框架,它更像是一个集各家之长的框架,从一个空壳开始,把需要的、适合的组件组装起来。例如它没有模版引擎,如果你确实需要用它实现一个web应用要渲染模版,你可以再组合你想要的选择,当然还可以用Starlette内置的Jinja2(是的,也是Flask内置的)。

### 为什么说Flask已死

上面提的是FastAPI的优势,但是也不能说明Flask已死,我为什么会这么觉得呢? 主要还是看开发者和用户的人气。

这个「人气」是一个很主观的感受,我能想到的有如下指标:

1. 社区活跃度。例如项目的Issue和Pull Request数量,Flask都是个位数,和FastAPI相比根本不是一个水平。这其实侧面证明项目不再活跃,因为如果活跃的话,老的用户会有更多需求,它们不来说明已经离开,而新的用户意味着有各种问题,文档即便足够全,其实我们要知道还是会有很多用户来提问和贡献代码的,没有就说明用得少。
2. 讨论度。也就是博客文章,Stackoverflow等网站咨询和讨论的热度,其实可以感受到,已经没什么人写Flask相关的内容了。
3. 开发迭代的频率。翻一下commits,可以看到Flask只有一个维护者会偶尔修修bug,没有什么大的功能特性开发。
4. 灵魂人物的影响力。Flask的灵魂人物,也就是项目的发起人其实早就不再参与项目了,搜一下项目贡献记录可以看到Armin Ronacher上次参与开发已经是6年前了。

以上种种在我这里其实都说明Flask已死,大家应该考虑替代品。

哎,有一点伤感,感谢Flask带我入了Web开发的坑。

### 后记

是的,我认为现在是抛弃Flask的时候了,如果你是一个Python Web服务的初学者请直接使用FastAPI,如果你是一个有一定工作经验的人,我建议下一个项目请使用FastAPI甚至替代现在的项目,欢迎讨论~

### 延伸阅读

1. https://lp.jetbrains.com/python-developers-survey-2022
2. https://fastapi.tiangolo.com/alternatives/
3. https://peps.python.org/pep-3333/
4. https://asgi.readthedocs.io/en/latest/introduction.html
5. https://www.encode.io/articles/hello-asgi
6. https://fastapi.tiangolo.com/deployment/server-workers/

0 comments on commit 2ef1bf8

Please sign in to comment.