关于flask:无脑吹FastAPI性能碾压Flask关于网上不合适的性能对比以及让我糊涂的自测结果

不止一次的听过,有个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 Flask
    from waitress import serve
    
    app = 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 FastAPI
    import uvicorn
    
    app = 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 hits
    Availability:                 100.00 %
    Elapsed time:                   9.15 secs
    Data transferred:               0.11 MB
    Response time:                  0.03 secs
    Transaction rate:             500.66 trans/sec
    Throughput:                     0.01 MB/sec
    Concurrency:                   14.93
    Successful transactions:        4579
    Failed transactions:               0
    Longest transaction:            0.10
    Shortest transaction:           0.02
  • flask + waitress

    Transactions:                  12598 hits
    Availability:                 100.00 %
    Elapsed time:                  10.02 secs
    Data transferred:               0.31 MB
    Response time:                  0.01 secs
    Transaction rate:            1257.03 trans/sec
    Throughput:                     0.03 MB/sec
    Concurrency:                   14.89
    Successful transactions:       12598
    Failed transactions:               0
    Longest transaction:            0.03
    Shortest transaction:           0.00
  • fastapi + uvicorn

    Transactions:                   5278 hits
    Availability:                 100.00 %
    \Elapsed time:                  9.05 secs
    Data transferred:               0.09 MB
    Response time:                  0.03 secs
    Transaction rate:             583.20 trans/sec
    Throughput:                     0.01 MB/sec
    Concurrency:                   14.93
    Successful transactions:        5278
    Failed transactions:               0
    Longest transaction:            0.11
    Shortest transaction:           0.01
  • fastapi + uvicorn + async

    Transactions:                   5876 hits
    Availability:                 100.00 %
    \Elapsed time:                  9.31 secs
    Data transferred:               0.10 MB
    Response time:                  0.02 secs
    Transaction rate:             631.22 trans/sec
    Throughput:                     0.01 MB/sec
    Concurrency:                   14.84
    Successful transactions:        5876
    Failed transactions:               0
    Longest transaction:            0.12
    Shortest 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 hits
Availability:                 100.00 %
Elapsed time:                   9.07 secs
Data transferred:               0.19 MB
Response time:                  0.02 secs
Transaction rate:             825.84 trans/sec
Throughput:                     0.02 MB/sec
Concurrency:                   14.89
Successful transactions:        7492
Failed transactions:               0
Longest transaction:            0.07
Shortest 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 hits
Availability:                 100.00 %
Elapsed time:                   9.24 secs
Data transferred:               0.13 MB
Response time:                  0.02 secs
Transaction rate:             842.39 trans/sec
Throughput:                     0.01 MB/sec
Concurrency:                   14.92
Successful transactions:        7782
Failed transactions:               0
Longest transaction:            0.15
Shortest 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上位。

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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理