原文转载自「刘悦的技术博客」v3u.cn/a_id_167python
也许这一篇的标题有那么一点不厚道,由于Asgi(Asynchronous Server Gateway Interface)毕竟是Wsgi(Web Server Gateway Interface)的扩展,而FastAPI毕竟也是站在Flask的肩膀上才有了日新月异的发展,大多数人据说Asgi也许是由于Django的最新版(3.0)早已宣布支持Asgi网络规范,这显然是一个振奋人心的消息,2020年,若是你在Web开发面试中不扯一点Asgi,显然就有点落后于形势了。web
那么到底啥是Wsgi,什么又是Asgi,放心,不扯CGI,不扯各类抽象概念,简单粗暴理解:面试
Wsgi是同步通讯服务规范,客户端请求一项服务,并等待服务完成,只有当它收到服务的结果时,它才会继续工做。固然了,能够定义一个超时时间,若是服务在规定的时间内没有完成,则认为调用失败,调用方继续工做。数据库
Wsgi简单工做原理示意图:apache
简单实现:flask
#WSGI example
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return b'Hello, Wsgi\n'
复制代码
Asgi是异步通讯服务规范。客户端发起服务呼叫,但不等待结果。调用方当即继续其工做,并不关心结果。若是调用方对结果感兴趣,有一些机制可让其随时被回调方法返回结果。api
Asgi简单工做原理示意图:浏览器
简单实现:bash
#Asgi example
async def application(scope, receive, send):
event = await receive()
...
await send({"type": "websocket.send", ...})
复制代码
简单总结一下:Asgi是异步的,Wsgi是同步的,而基于Wsgi的Flask是同步框架,基于Asgi的FastAPI是异步框架,就这么简单,那么同步框架和异步框架的区别到底在哪儿?为何要把Flask换成FastAPI?服务器
不靠拍脑门儿、也不是道听途说、人云亦云。玩技术的应该用数听说话,论点永远依托论据,因此咱们来简单对两款框架的性能作一个测试,首先分别安装依赖的库。
Flask:
pip install gunicorn
pip install gevent
pip install flask
复制代码
FastAPI:
pip install fastapi
pip install uvicorn
复制代码
咱们首先干的一件事就是,看看Flask和FastAPI如何处理来自多个客户端的多个请求。特别是当代码存在效率问题时(好比数据库查询时间长这种耗时任务),这里故意使用time.sleep()来模拟耗时任务,为何不用asyncio呢?由于众所周知的缘由:time.sleep是阻塞的。
Flask:
from flask import Flask
from flask_restful import Resource, Api
from time import sleep
app = Flask(__name__)
api = Api(app)
class Root(Resource):
def get(self):
print('睡10秒')
sleep(10)
print('醒了')
return {'message': 'hello'}
api.add_resource(Root, '/')
if __name__ == "__main__":
app.run()
复制代码
FastApi:
import uvicorn
from fastapi import FastAPI
from time import sleep
app = FastAPI()
@app.get('/')
async def root():
print('睡10秒')
sleep(10)
print('醒了')
return {'message': 'hello'}
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8000)
复制代码
分别启动服务
Flask:python3 manage.py
FastAPI:uvicorn manage:app --reload
同时一时间内,开启多个浏览器,分别并发请求首页 。
Flask:http://localhost:5000
FastAPI:http://localhost:8000
观察后台打印结果:
Flask:
FastAPI:
能够看到,一样的四次请求,Flask先是阻塞了40秒,而后依次返回结果,FastAPI则是第一次阻塞后直接返回,这表明了在FastAPI中阻塞了一个事件队列,证实FastAPI是异步框架,而在Flask中,请求多是在新线程中运行的。将全部CPU绑定的任务移到单独的进程中,因此在FastAPI的例子中,只是在事件循环中sleep(因此异步框架这里最好不要使用time.sleep而是asyncio.sleep)。在FastAPI中,异步运行IO绑定的任务。
固然这不能说明太多问题,咱们继续使用鼎鼎有名的ApacheBench分别对两款框架进行压测。
一共设置5000个请求,QPS是100(请原谅个人机器比较渣)。
ab -n 5000 -c 100 http://127.0.0.1:5000/
ab -n 5000 -c 100 http://127.0.0.1:8000/
复制代码
这里为了公平起见,Flask配合Gunicorn服务器,开3个worker,FastAPI配合Uvicorn服务器,一样开3个worker。
Flask压测结果:
liuyue:mytornado liuyue$ ab -n 5000 -c 100 http://127.0.0.1:5000/
This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requests
Server Software: gunicorn/20.0.4
Server Hostname: 127.0.0.1
Server Port: 5000
Document Path: /
Document Length: 28 bytes
Concurrency Level: 100
Time taken for tests: 4.681 seconds
Complete requests: 5000
Failed requests: 0
Total transferred: 1060000 bytes
HTML transferred: 140000 bytes
Requests per second: 1068.04 [#/sec] (mean)
Time per request: 93.629 [ms] (mean)
Time per request: 0.936 [ms] (mean, across all concurrent requests)
Transfer rate: 221.12 [Kbytes/sec] received
复制代码
FastAPI压测结果:
liuyue:mytornado liuyue$ ab -n 5000 -c 100 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requests
Server Software: uvicorn
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /
Document Length: 19 bytes
Concurrency Level: 100
Time taken for tests: 2.060 seconds
Complete requests: 5000
Failed requests: 0
Total transferred: 720000 bytes
HTML transferred: 95000 bytes
Requests per second: 2426.78 [#/sec] (mean)
Time per request: 41.207 [ms] (mean)
Time per request: 0.412 [ms] (mean, across all concurrent requests)
Transfer rate: 341.27 [Kbytes/sec] received
复制代码
显而易见,5000个总请求,Flask花费4.681秒,每秒能够处理1068.04个请求,而FastAPI花费2.060秒,每秒能够处理2426.78个请求。
结语:曾几什么时候,当人们谈论Python框架的性能时,老是不自觉的嗤之以鼻 ,而如今,Python异步生态正在发生着惊天动地的变化,新的框架应运而生(Sanic、FastAPI),旧的框架正在重构(Django3.0),不少库也开始支持异步(httpx、Sqlalchemy、Mortor)。软件科技发展的历史代表,一项新技术的出现和应用,经常会给这个领域带来深入的变革,古语有云:察势者智,顺势者赢,驭势者独步天下。因此,只有拥抱将来、拥抱新技术、顺应时代才是正确的、可持续发展的道路。
原文转载自「刘悦的技术博客」 v3u.cn/a_id_167