Python Web 框架性能研究
三个方面:性能上,应用场景上,框架本身特点
性能上:
性能测试工具基本介绍:测试环境: 电脑环境:win10 i5 4G独显 8G内存 ubuntu18.04 python3.6.8 ab 2.3 python2.7
ab是Apache超文本传输协议(HTTP)的性能测试工具。 主要用它来测试框架每秒处理的请求数
并发连接数:某个时刻服务器所接受的请求数目
并发用户数:简单理解就是用户数
吞吐量(率):每秒处理的请求数
服务器平均请求等待时间: 处理完成所有请求数所花费的时间 / 总请求数
简单理解就是:处理每个请求平均花费的时间,单位是毫秒
执行原理 例如:1000并发连接数 100并发用户数指的是 模拟100用户在同一时刻连续不断的发送1000个请求给服务器
测试分为5组,
分别是 100并发连接数 100并发用户数
1000并发连接数 100并发用户数
10000并发连接数 100并发用户数
10000并发连接数 500并发用户数
10000并发连接数 1000并发用户数
每组数据测了5次求的平均值
# flask
@app.route("/hello")
def hello_test():
grate = 85
if grate > 90:
res = "非常优秀"
elif grate > 80:
res = "优秀"
elif grate > 70:
res = "良好"
elif grate > 60:
res = "及格"
else:
res = "不及格"
return res
# tornado
class IndexHandler(tornado.web.RequestHandler):
def get(self,*args,**kwargs):
grate = 85
if grate > 90:
res = "非常优秀"
elif grate > 80:
res = "优秀"
elif grate > 70:
res = "良好"
elif grate > 60:
res = "及格"
else:
res = "不及格"
self.write(res)
# sanic
@app.route("/")
async def index(request):
grate = 85
if grate > 90:
res = "非常优秀"
elif grate > 80:
res = "优秀"
elif grate > 70:
res = "良好"
elif grate > 60:
res = "及格"
else:
res = "不及格"
return text(res)
# fastapi
@app.get("/")
async def root():
grate = 85
if grate > 90:
res = "非常优秀"
elif grate > 80:
res = "优秀"
elif grate > 70:
res = "良好"
elif grate > 60:
res = "及格"
else:
res = "不及格"
return res
测试结果:
第一吞吐量测试
结论:GET请求中,sanic,fastapi框架每秒处理的请求出最多,其次是tornado和flask+gevent
第二用户平均等待时间
结论:当并发用户数比较小时,各各框架之间用户平均等待时间相差是不大的,当并发用户数达到较高时,sanic框架和fastapi框架明显在用户平均等待时间上远远小于其他框架,性能更好
#flask
@app.route("/login",methods=["POST","GET"])
def login_test():
if request.method == "GET":
return render_template("index.html")
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
if username == "test" and password == "test":
return "%s,login success
"%username
else:
return "login failed
"
# tornado
class PostHandler(tornado.web.RequestHandler):
def post(self,*args,**kwargs):
username = self.get_argument("username")
password = self.get_argument("password")
if username == "test" and password == "test":
self.write("%s,login success
"%username)
else:
self.write("login failed
")
# sanic
@app.route('/login',methods=["GET","POST"])
async def login(request):
if request.method == "GET":
return await response.file("./index.html")
elif request.method == 'POST':
username = request.form.get("username")
password = request.form.get("password")
if username == "test" and password == "test":
return html('login success
')
else:
return html('login fail
')
# fastapi
@app.post("/login")
async def insert(people:People):
username = people.username
password = people.password
if username == "test" and password == "test":
return {"success":True}
else:
return {"success":False}
第一吞吐量
结论:在POST请求上,sanic框架上远远高于其他框架,其次是fastapi,tornado和flask+gevent相差不大
第二用户平均等待时间
结论:
当并发用户较小时,每个框架用户平均等待时间是相差不大的,当处于高的并发用户时,sanic和fastapi性能上要明显比其他框架快,时间短
同时我们也发现,flask+gevent模块后,用户平均等待时间从1523直接降至690直接提升了2倍左右的性能
# flask
@app.json_test()
def json_test():
shop = {
"store" :{
"book":[
{
"title":"富爸爸穷爸爸",
"category":"投资理财",
"author":"罗伯特",
"price":20.
}
{
"title":"小狗钱钱",
"category":"投资理财",
"author":"博多舍费尔",
"price":15,
}
{
"title":"硅谷热",
"category":"科技",
"author":"朱迪丝",
"price":60,
}
{
"title":"大数据时代",
"category":"科技",
"author":"肯尼斯",
"price":50,
}
],
"bicycle":{
"color":"red",
"price":35
}
}
}
return json(shop)
# sanic
@app.route("/json")
async def test_json(request):
shop = {
"store" :{
"book":[
{
"title":"富爸爸穷爸爸",
"category":"投资理财",
"author":"罗伯特",
"price":20.
}
{
"title":"小狗钱钱",
"category":"投资理财",
"author":"博多舍费尔",
"price":15,
}
{
"title":"硅谷热",
"category":"科技",
"author":"朱迪丝",
"price":60,
}
{
"title":"大数据时代",
"category":"科技",
"author":"肯尼斯",
"price":50,
}
],
"bicycle":{
"color":"red",
"price":35
}
}
}
return json(shop)
# fastapi
@app.get("/json")
async def josn_test():
shop = {
"store" :{
"book":[
{
"title":"富爸爸穷爸爸",
"category":"投资理财",
"author":"罗伯特",
"price":20.
}
{
"title":"小狗钱钱",
"category":"投资理财",
"author":"博多舍费尔",
"price":15,
}
{
"title":"硅谷热",
"category":"科技",
"author":"朱迪丝",
"price":60,
}
{
"title":"大数据时代",
"category":"科技",
"author":"肯尼斯",
"price":50,
}
],
"bicycle":{
"color":"red",
"price":35
}
}
}
return shop
第一吞吐量
处理json上,sanic框架依然是最快的,是tornado框架的2倍,每秒处理请求高达2000多
第二用户平均等待时间
从JSON序列化,我们可以看出,sanic在处理很高的并发用户时,要比其他框架很快用户平均等待时间更短,flask+gevent框架在用户平均等待时间上差不多
# flask
@app.route("/template")
@app.route("/template/")
def template_test(name = None):
return render_template("index.html",name=name)
# sanic
@app.route("/html")
async def index(request):
return await response.file("./index.html")
# fastapi
@app.get('/html')
async def html_test(request:Request):
return templates.TemplateResponse("index.html",{"request":request})
第一吞吐量
在模板处理上我们发现最快的是fastapi框架达到1600是其他框架的2倍左右
第二是用户平均等待时间
从数据中我们发现,当处理较高的并发用户时,fastapi的性能是最好的
当处理低的并发用户时各个框架之间是相差不大的
第一吞吐量
第二用户平均等待时间
结论:从GET请求可以看出,python2和python3环境对于flask+gevent来说没有什么差异的
post请求 吞吐量
用户平均等待时间
在处理POST请求上,两个环境也是没有什么很大影响的
JSON序列化
第一吞吐量
第二 用户平均等待时间
对于json序列化来说,两个环境也是没有多大影响的
模板渲染
第一吞吐量
第二 用户平均等待时间
在模板渲染上,python2和python3环境对于flask+gevent是没有很大影响的
第一:从GET,POST,JOSN,模板四个方面可以看出
1. 在处理GET,POST,JSON这三方面时,sanic是最快的 fastapi稍微差一点,tornado和flask+gevent处理能力差不多 是sanic的一半左右
2.在处理模板渲染时,fastapi框架是最快的,几乎是其他框架 的1倍左右,tornado,sanic,flask+gevent处理能力差不多
3.flask框架处理能力最差,flask+gevent模块后可以提升2倍左右 的性能,和tornado框架差不多
4. python的版本不影响flask+gevent框架在性能上的差别
原理:
sanic框架:
基于asyncio-Python的异步编程工具箱
sanic把eventloop从async替换成了uvloop
http解析器采用的高性能的httptools fastapi框架
基于 Starlette(轻量级的 ASGI 框架) 和
Pydantic(基于Python类型提示来定义数据验证, 序列化和文档)
tornado框架:
主要是基于异步非阻塞模型
内部封装了协程模块
内部有对epoll的使用
flask: 轻量级,主要是用来写接口的一个框架,实现前后端分离,提高开发效率。Flask本身相当于一个内核,其他几乎所有的功能都需要用第三方的扩展来实现。其WSGI工具箱用Werkzeug(路由模块),模板引擎则使用Jinja2,这两个也是Flask框架的核心
tornado: 是一种Web服务器软件的开源版本。Tornado和现在的主流Web服务器框架(包括大多数Python的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其非阻塞的方式和对epoll的运用 Tornado每秒可以处理数以千计的连接,因此Tornado是实时Web服务的一个理想框架
sanic: Sanic在处理长连接时特别有用,比如 websocket如果需要支持websockets或 进行大量持久的外部API调用 新功能方面,Sanic与flask相似,比如 通过共享Blueprints的概念,微小的子 应用程序,允许开发人员在更大的应用 程序中拆分和组织其代码 另外,Sanic框架非常快。其中一个依 赖项是Uloop,据官方文档表示可以让 asyncio的效率提高了2-4倍
fastapi: 自动生成API文档:编写API接口后,你就可以使用符合标准的UI如SwaggerUI,ReDoc等来使用APi 性能快:高性能,可以和NodeJS和Go相提并论 标准化:基于并完全兼容API的开发标准:OpenAPI(以前称为Swagger)和JSON Schema
flask:通过路由装饰器注解的methods属性来指定视图处理函数可以接收那种请求方式 @app.route("/", methods=["get", "post"..])
tornado:可以通过直接重写父类RequestHandler中的get/post/..的请求处理方法来实现不同的请求方式的区分
sanic:通过路由装饰器注解的methods属性来指定视图处理函数可以接收那种请求方式,函数名以async开始 @app.route("/", methods=["get", "post"..]) async def xxx(): return xxx
fastapi:通过装饰器.方法名接受请求 app.get('/') async def xxx(): return xxx
flask:默认templates/中保存网页模板;static/中 保存静态资源,不需要配置
tornado:通过tornado.web.Application中的配置选项 template_path配置网页模板文件夹位置,static_path配置静态资源文件夹位置
sanic:静态文件和目录(如图像文件)在注册到 app.static() 方法 app.static('/static', './static')
fastapi:静态文件和目录(如图像文件)在注册到 app.mount() 方法 app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates")
flask:默认使用第三方的jinja2模板语法,是在DTL语法的基础上完善的一种专门给python使用的模板语法
tornado:默认使用jinja模板语法:经过一定改造的模板语法
sanic:本身不带模板语法,需要安装模板语法
fastapi:本身不带模板语法,需要安装模板语法
flask:需要同时部署和配置 http server 和 wsgi server ,如果想支持异步还要部署 worker ,复杂度高
tornado:tornado 开发的应用因为自己实现了高效 http 处理的应用只需要部署自己就可以了,相对简单
sanic:非常简单:使用内置web服务器 ASGI webserver 或 gunicorn 或者 把Sanic放在反向代理后面如nginx
fastapi:可以使用uvicorn,或者放在反向代理后面nginx,等比较方便