当前位置: 首页 > 后端技术 > Python

2020年是时候更新你的技术武器库了:AsgivsWsgi(FastAPIvsFlask)

时间:2023-03-25 21:33:27 Python

一点都不厚道,因为Asgi(AsynchronousServerGatewayInterface)毕竟是Wsgi(WebServerGatewayInterface)的扩展,而且FastAPI毕竟是站在了Flask的肩膀上发展了突飞猛进。大多数人听说Asgi可能是因为Django的最新版本(3.0)已经宣布支持Asgi网络规范,这显然是一个振奋人心的消息。2020年,如果你的web开发面试不谈Asgi,显然会有点落伍了。那么什么是Wsgi,什么是Asgi,别着急,不讲CGI,不讲各种抽象概念,简单粗暴的理解:Wsgi是一种同步通信服务规范,客户端请求一个服务,等待对于服务的完成,只有当它收到服务的结果时才会继续工作。当然,您可以定义超时时间。如果服务未在规定时间内完成,则视为调用失败,调用方继续工作。Wsgi简单工作原理示意图:简单实现:#WSGI例子defapplication(environ,start_response):start_response('200OK',[('Content-Type','text/plain')])returnb'Hello,Wsgi\n'Asgi是异步通信服务的规范。客户端发起服务调用,但不等待结果。调用者立即继续其工作,而不关心结果。如果调用者对结果感兴趣,则可以通过回调方法随时返回结果的机制。Asgi简单工作原理示意图:简单实现:#Asgiexampleasyncdefapplication(scope,receive,send):event=awaitreceive()...awaitsend({"type":"websocket.send",...})简单总结一下:Asgi是异步的,Wsgi是同步的,基于Wsgi的Flask是同步框架,基于Asgi的FastAPI是异步框架。就这么简单,那么同步框架和异步框架有什么区别呢?为什么要用FastAPI代替Flask?它不靠头脑风暴,也不靠道听途说或附和。玩技术的要用数据说话,论据永远靠论据,所以我们简单测试一下两个框架的性能,先分别安装依赖库。Flask:pipinstallgunicornpipinstallgeventpipinstallflaskFastAPI:pipinstallfastapipipinstalluvicorn我们要做的第一件事就是了解Flask和FastAPI如何处理来自多个客户端的多个请求。尤其是当代码中存在效率问题时(比如长时间数据库查询等耗时任务),这里特意使用time.sleep()来模拟耗时任务。为什么不使用异步?出于众所周知的原因:time.sleep正在阻塞。Flask:fromflaskimportFlaskfromflask_restfulimportResource,Apifromtimeimportsleepapp=Flask(__name__)api=Api(app)classRoot(Resource):defget(self):print('睡眠10秒')sleep(10)print('醒来')return{'message':'hello'}api.add_resource(Root,'/')if__name__=="__main__":app.run()FastApi:importuvicornfromfastapiimportFastAPIfromtimeimportsleepapp=FastAPI()@app.get('/')asyncdefroot():print('睡眠10秒')sleep(10)print('醒来')return{'message':'hello'}if__name__=="__main__":uvicorn.run(app,host="127.0.0.1",port=8000)分别启动服务Flask:python3manage.pyFastAPI:uvicornmanage:app--reloadat同时打开多个浏览器,并发请求首页。Flask:http://localhost:5000FastAPI:http://localhost:8000观察后台打印结果:Flask:FastAPI:可以看到对于同样的四个请求,Flask先是阻塞了40秒,然后返回结果在转而,whileFastAPI是在第一个block之后直接返回的,这意味着在FastAPI中阻塞了一个事件队列,这就证明了FastAPI是一个异步框架,而在Flask中,请求可能会在一个新的线程中运行。将所有CPU密集型任务移动到一个单独的进程中,因此在FastAPI的情况下,只需在事件循环中休眠(因此异步框架最好不要在这里使用time.sleep,而是使用asyncio.sleep)。在FastAPI中,异步运行IO绑定任务。当然,这并不能说明太多问题。我们继续使用知名的ApacheBench对两个框架分别进行测试。一共设置了5000个请求,QPS为100(请原谅我的渣机)。ab-n5000-c100http://127.0.0.1:5000/ab-n5000-c100http://127.0.0.1:8000/这里为了公平起见,Flask配合Gunicorn服务器开启3个worker,FastAPI有了Uvicorn服务器,也开了3个worker。Flask压力测试结果:liuyue:mytornadoliuyue$ab-n5000-c100http://127.0.0.1:5000/这是ApacheBench,版本2.3<$Revision:1826891$>版权所有1996AdamTwiss,ZeusTechnologyLtd,http://www.zeustech.net/授权给Apache软件基金会,http://www.apache.org/基准测试127.0.0.1(请耐心等待)已完成500个请求已完成1000个请求已完成1500个请求已完成2000个请求已完成2500个请求已完成3000个请求已完成3500个请求已完成4000个请求已完成4500个请求已完成5000个请求已完成5000个请求服务器软件:gunicorn/20.0.4服务器主机名:127.0.0.1服务器端口:5000文档路径:/文档长度:28字节并发级别:100所用时间用于测试:4.681秒完成请求:5000失败请求:0总传输:1060000字节HTML传输:140000字节每秒请求数:1068.04[#/sec](平均值)每个请求时间:93.629[ms](平均值)每个请求时间:0.936[ms](所有并发请求的平均值)传输速率:221.12[Kbytes/sec]receivedFastAPI压力测试结果:liuyue:mytornadoliuyue$ab-n5000-c100http://127.0.0.1:8000/这是ApacheBench,版本2.3<$Revision:1826891$>版权所有1996AdamTwiss,ZeusTechnologyLtd,http://www.zeustech.net/授权给Apache软件基金会,http://www.apache.org/基准测试127.0.0.1(耐心等待)完成500个请求完成1000个请求完成1500个请求完成2000个请求完成2500个请求完成3000个请求完成3500个请求完成4000个请求完成4500个请求完成5000个请求完成5000个请求服务器软件:uvicorn服务器主机名:127.0.0.1服务器端口:8000文件路径:/document长度:19字节并发级别:100测试时间:2.060秒完成请求:5000失败请求:0总传输量:720000字节传输HTML:95000字节每秒请求数:2426.78[perquemean](:41.207[ms](平均值)每个请求的时间:0.412[ms](平均值,跨越所有并发请求)传输速率:341.27[Kbytes/sec]收到显然,总共5000个请求,Flask需要4.681秒,每秒可以处理1068.04个请求,而FastAPI需要2.060秒,每秒可处理2426.78个请求。新框架不断涌现(Sanic、FastAPI),老框架正在重构(Django3.0),许多库开始支持异步(httpx、SQLAlchemy、Mortor)。软件技术发展表明,一项新技术的出现和应用往往会给这个领域带来深刻的变化,古语有云:观势者智,顺势者胜,顺势者主宰世界。因此,只有拥抱未来、拥抱新技术、与时俱进,才是正确的、可持续的发展之路。原文转载自《刘越的技术博客》https://v3u.cn/a_id_167