不止一次的听过,有个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上位。

连写文带测试花了几个小时,闲的。