不止一次的听过,有个FastAPI框架,性能碾压Flask,直追Golang,不过始终没有测试过,明天闲着没事测试一下看看后果。不晓得是哪里出了问题,后果大跌眼镜。
测试之前
为了偷懒,天然想先从网上找找前人的测试代码以作为参照。百度前几名对于FastAPI和Flask性能测试又带了代码的有上面几个:
- FastAPI、Flask、Golang性能测试
- Flask、Django、Tornado、FastAPI 之 Python Web 并发测试
- flask,tornado,fastapi 压测比拟(web框架)
有点纳闷
简略看了一下,没明确,为什么都用了unicorn启动FastAPI,却只用Flask自带的启动形式,为什么不必其余WSGI服务器?
我感觉这样应该是有问题的,且不说原本二者都不是同一档次的框架(FastAPI是基于Starlette的,这才是应该和Flask比照的框架),就算比照,也应该用差不多的启动形式吧?
unicorn是个第三方ASGI服务器,Flask应该用一个第三方WSGI服务器来启动才失常吧?感觉用它自带的WSGI服务器比可能不太偏心。
我原本想用gunicorn来启动Flask进行比照的,后果发现不兼容Windows,所以换了个waitress,差不多的WSGI框架。
开始测试
网上都是用AB测试的,我电脑没装Apache,就用了另一个测试工具siege。测试形式为不限连接数,测试10秒,命令如下:
./siege.exe -b -t10s http://127.0.0.1:5000/
测试代码和之前搜到的一样,用二者官网的例子,输入HelloWorld,略作批改,把启动代码写进文件内,就不必应用命令行启动了。
Flask
from flask import Flaskfrom waitress import serveapp = Flask(__name__)@app.route('/')def index(): return {'message': 'hello world'}if __name__ == '__main__': app.run(host='0.0.0.0') # serve(app, host='0.0.0.0', port=5000)
FastAPI
from fastapi import FastAPIimport uvicornapp = FastAPI()@app.get("/")async def read_root(): return {"Hello": "World"}if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=5000)
测试后果
鉴于网上的文章在那摆着,所以我也测试了一下应用Flask自带启动形式的后果。
除此之外,还测试了FastAPI应用异步的后果(就加了个async,理论应该什么没用的,文档中明确说了,只有函数外部应用了异步函数且须要同步返回时,也就是须要在外部用await时,才须要定义async)。
后果如下:
flask
Transactions: 4579 hitsAvailability: 100.00 %Elapsed time: 9.15 secsData transferred: 0.11 MBResponse time: 0.03 secsTransaction rate: 500.66 trans/secThroughput: 0.01 MB/secConcurrency: 14.93Successful transactions: 4579Failed transactions: 0Longest transaction: 0.10Shortest transaction: 0.02
flask + waitress
Transactions: 12598 hitsAvailability: 100.00 %Elapsed time: 10.02 secsData transferred: 0.31 MBResponse time: 0.01 secsTransaction rate: 1257.03 trans/secThroughput: 0.03 MB/secConcurrency: 14.89Successful transactions: 12598Failed transactions: 0Longest transaction: 0.03Shortest transaction: 0.00
fastapi + uvicorn
Transactions: 5278 hitsAvailability: 100.00 %\Elapsed time: 9.05 secsData transferred: 0.09 MBResponse time: 0.03 secsTransaction rate: 583.20 trans/secThroughput: 0.01 MB/secConcurrency: 14.93Successful transactions: 5278Failed transactions: 0Longest transaction: 0.11Shortest transaction: 0.01
fastapi + uvicorn + async
Transactions: 5876 hitsAvailability: 100.00 %\Elapsed time: 9.31 secsData transferred: 0.10 MBResponse time: 0.02 secsTransaction rate: 631.22 trans/secThroughput: 0.01 MB/secConcurrency: 14.84Successful transactions: 5876Failed transactions: 0Longest transaction: 0.12Shortest transaction: 0.00
从Transaction rate也就是申请解决速率能够看到:
- Flask间接启动后果比FastAPI启动后果略差一些(500:583/631)
- FastAPI用不必异步async差异不大(583:631)
- Flask用waitress WSGI服务器启动后果比不必快了2.5倍(1257:500),同样也比FastAPI快2倍左右
这个后果和其他人测试的齐全不同,与我预估的也有差距,感觉是哪里出错了?
Flask间接启动比FastAPI慢一点是在意料之中的,然而应用waitress WSGI服务器启动后快这么多必定也是不失常的。
于是我去查看了二者启动的源码,发现waitress默认4线程,unicorn默认1线程。。。
只好把Flask批改为1线程从新测试
serve(app, host='0.0.0.0', port=5000, threads=1)
后果如下:
Transactions: 7492 hitsAvailability: 100.00 %Elapsed time: 9.07 secsData transferred: 0.19 MBResponse time: 0.02 secsTransaction rate: 825.84 trans/secThroughput: 0.02 MB/secConcurrency: 14.89Successful transactions: 7492Failed transactions: 0Longest transaction: 0.07Shortest transaction: 0.01
把unicorn批改为4线程从新测试
uvicorn.run("test-fastapi:app", host="0.0.0.0", port=5000, workers=4)# 须要同目录下新建`pyproject.toml`文件,内容为:[tool.poetry.scripts]start = "test-fastapi:start"
后果如下:
Transactions: 7782 hitsAvailability: 100.00 %Elapsed time: 9.24 secsData transferred: 0.13 MBResponse time: 0.02 secsTransaction rate: 842.39 trans/secThroughput: 0.01 MB/secConcurrency: 14.92Successful transactions: 7782Failed transactions: 0Longest transaction: 0.15Shortest transaction: 0.00
能够看出:
- Flask用waitress WSGI服务器单线程启动后果比不必快了65%(825:500),同样也比FastAPI快很多(825:583/631)
- unicorn用4线程启动晋升很小(842:583/631),和waitress单线程差不多
这个后果也很出其不意,我当初有点不自信了,是我测试过程哪里不对吗?
实践上说不通啊,unicorn开4线程后后果只有1倍多,waitress开4线程快了2倍多,代表着4线程都没齐全利用到,而且unicorn单线程足解决能力更强吧,不晓得为什么后果差这么多。
可能是测试工具的起因吧,毕竟他人都用的AB,还都指定并发数,我用的siege,没限度并发。
而且unicorn文档还提到能够应用Gunicorn治理过程,可能性能还会晋升,碍于设施起因我就不测试了。
写在最初
做这个测试的本意是反驳前文提到的起因,只是想说,比照测试时应该应用第三方WSGI服务器启动Flask。
当初最终测试后果我也不敢确定了,只能保障测试数据和代码相对实在,看到本文的敌人最好本人测试一遍,顺便通知我为什么会呈现这个后果。
还是多说一句,网上太多无脑吹FastAPI的人了,不否定它的长处,比方反对异步、ws、主动生成文档、强调申明变量类型等,但也没必要死踩Flask上位。
连写文带测试花了几个小时,闲的。