首先:
- 没有专用的服务器
- 没有测试专用的代码片段
- 没有牛人背书
这只是一个简单的对比: 用一台普通的机器,以尽量相同的方式分别部署不同Web框架编写的一段简单程序.然后使用压力测试程序run一下,做个chart出来.直观的反应一下. .python的常用框架性能之间的差别.较真的杠精现在就可以出门左转了.
先要介绍一下我的测试环境: acer的商务机,具体配置是酷睿8,8g,1t的5400转机械硬盘, 操作系统是ubuntu 18.04 desktop
本次使用的代码特别简单,所以因为个人能力不济造成性能下降的可能性比较小,哈哈.本次测试的是一些常用的python的Web开发框架.下面有请选手登场:
- Django 不用说,最早进入中国的python web框架之一, 一站式结构, 文档齐全, 功能强大.用户众多,入坑首选之一
- Flask 知名度和Django在伯仲之间的python web框架,和相对重型的Django不同,flask标榜自己的轻量级, 做个单纯的web框架,只负责路由和视图部分,其他的交给插件部分(flask众多的插件也是亮点之一).入坑首选之二
- AioHttp 一个异步的web框架,包含服务端和客户端,推荐python 3.5+, 视图函数是异步写法.也是因为异步,所以性能出色.
- Sanic 也是异步类flask的web框架,无需插件即支持websocket,因为是类flask框架,所以从flask 转过来的话无论学习还是维护成本都是极低的.性能自己说也是非常高的.在国外有大量的生产环境案例. 插件/中间件很丰富.
- Tornado 是一个facebook开源的异步框架,自己的文档说速度相当快,国内也有很多人这么说,我不怕剧透,其实他的性能从4.2时代就已经很落伍了.而且由于他的异步机制是自己搞的一套.很多东西写法都很独特.学习成本较高.所以,本人是不推荐学习的.也没任何优势而已,这里把他拉出来就是为了衬托同行.
- Bottle 一个超简洁的轻量级web框架.(5年之前)以性能著称.同步模式.国外国内都不算应用广.比flask更简洁,但是插件也比较少.
- Falcon 这个国内用的不多,但是国外用户还是很多的.以安全稳定著称(就是所谓的线程安全那种,你懂的),自说是性能和安全的最佳平衡.有很多生产环境的案例.主要是用于提供接口服务. 语法稍微繁琐一点.
- Vibora 一个很新的异步模式的类flask的web框架,flask开发者友好(要抢flask的饭碗?),性能也是变态的好.个人觉得不错.(毕竟类flask的框架,对插件的依赖是可有可无的)
很多人都知道Python语言的代码,以运行缓慢著称(我这是引用众数的观点.不抬杠),所以很多人诟病Python的web框架运行缓慢.不过,个人的观点是: 实务中, 特别当你不是那么大的分布式的部署的时候,性能瓶颈往往是压在数据库而不是web框架上.你可以根据自己的网站/业务的访问量计算一下你选中的Web框架是否能满足你的需求?
测试代码就是各自的文档中的hello world代码.部署上能用gunicorn的就用,有些部署比较特殊的框架那没办法,总是,尽量减少部署方式上的差异(python的web框架,部署方式对性能的影响还是非常大的).
测试方式使用siege做并发压力测试,从50客户端开始,每次测试递增50个客户端,一直到最后1000个客户端,每次5000个事务请求. 每个框架做400批次压力测试.最后的结果清洗后做个统计,使用pygal生成图表. x轴是客户端数量,y轴是每秒处理多少事务(TPS),所有的测试结果都是100%完成.
测试结果
Django
Flask
Bottle
Falcon
从这里开始,都是异步的框架了
Tornado
Sanic
AioHttp
Vibora
全家福
个人总结:
- 无论同步还是异步模式,所有的框架在低并发(50客户端以内)性能都是出奇的好.如果使用QPS的换算公式的话.你会发现,如果一般性类的网站(企业门户,个人博客之类),速度上完全没问题.
- 并发能力上来说,Django和Flask难兄难弟日常垫底儿.但这并不影响他们的广泛应用.而且,即使是他们的垫底性能,也能在1000客户端的情况下维持每秒1000上下的TPS.坦白的说,这算不上高性能,但是满足绝大多数站点(尤其是创业初期的产品原型)的需求是没问题了.
- 同步工作模式和异步工作模式相比,并发能力上全面落后挨打.甚至被秒杀.但是,异步工作模式在代码书写上是有要求的(有些coder常说的一步异步,处处异步并不是没有道理的).并且异步提升的是单位时间的处理能力.在你的服务器崩溃之前,异步工作模式并不会提供更高的处理能力.
- Tornado 成也性能,败也性能.在异步的时代,tornado以较高学习成本,捉急的性能,让成为拍在沙滩上的前浪.至少现在.不要说tornado的性能高什么的了.
- Vibora 性能确实变态. 即使1000客户端,也能维持超过1万的TPS.值得关注一下.
以上是空载的数据,如果加上本地的数据库负载(原子操作).所有的框架没有任何差别.瓶颈都在数据库IO上.
python的web框架多如牛毛(远不像国内的翻来覆去django,flask,tornado三大件).特点也是千差万别.基本上越新的框架越有后发的优势,我会在工作之余,做一些相关的对比工作.
代码片段(Hello World):
测试代码引自官方文档,未做任何优化.
Falcon
# -*- coding: utf-8 -*-
import falcon
from wsgiref import simple_server
app = falcon.API()
class ThingsResource(object):
def on_get(self, req, resp):
"""Handles GET requests"""
resp.status = falcon.HTTP_200 # This is the default status
resp.body = ("Hello Falcon!")
things = ThingsResource()
app.add_route('/query/', things)
if __name__ == "__main__":
httpd = simple_server.make_server('127.0.0.1', 8086, app)
httpd.serve_forever()
AioHttp
# -*- coding: utf-8 -*-
from aiohttp import web
route = web.RouteTableDef()
app = web.Application()
port = 8084
@route.get('/query/')
async def hello_world(request):
return web.Response(text="Hello, Aio!")
async def my_web_app():
app = web.Application()
app.add_routes(route)
return app
if __name__ == '__main__':
web.run_app(app=my_web_app(), host="0.0.0.0", port=port)
Bottle
# -*- coding: utf-8 -*-
from bottle import route, run, default_app
app = default_app()
@route('/query/')
def index():
return "Hello Bottle!"
if __name__ == "__main__":
run(app=app, host='0.0.0.0', port=8082, server="tornado")
Flask
# -*- coding: utf-8 -*-
from flask import Flask
app = Flask(__name__)
@app.route('/query/')
def hello_world():
return 'Hello Flask!'
if __name__ == '__main__':
app.run()
Sanic
# -*- coding: utf-8 -*-
from sanic import Sanic
from sanic import response
app = Sanic()
@app.route("/query/")
async def test(request):
request
return response.text("Hello Sanic!")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8083, debug=True)
pass
Tornado
# -*- coding: utf-8 -*-
import tornado.ioloop
import tornado.web
from tornado.httpserver import HTTPServer
from tornado import gen
from tornado.ioloop import IOLoop
class MainHandler(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
self.write("Hello, Tornado!")
def make_app():
return tornado.web.Application([
(r"/query/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
server = HTTPServer(app)
app.listen(8085)
server.start(0) # forks one process per cpu
print("tornado server run on 8085....")
IOLoop.current().start()
没有django的是因为django的代码太多,不方便贴. 有兴趣的自己去django手册看一下就好了.
写在最后
python的框架远远不止上面说的哪些, 可以说, 如果你想寻找一款最好的python开发框架,抱歉这个真没有.每个框架都有其存在的价值或者意义,尽管在某些方面看起来有些过时.和某些一两个框架独大的语言不同.python语言的框架是一种百花齐放百家争鸣的状态. 不过大体来说, python的web开发框架分2大类:
- 全能型的一站式框架
- 自助式的微框架
一站式框架
一站式框架提供了从路由,ctos,模板渲染,中间件, web-socket支持和orm等你想到的想不到的各种功能.有什么问题,看文档就行了. 语法的一致性好. 新需求导致的学习成本曲线平缓. 不太容易掉坑里. 一站式框架的典型代表是 Django.(发音类似: 姜戈,前面的d不发音)
微框架
微框架就是那种只提供基本功能的框架.在python中,这种提供单一功能的微框架忒多. 比如Flask仅仅提供了路由,蓝图之类的基本功能.(Flask模板还是借助jinja2来实现的,当然你也可以使用其他模板). 其他的功能,都需要你借助插件或者库来完成.比如说ORM方面,sqlalchemy, peewee, pony这些orm框架仅仅提供orm功能.你可以接触插件或者自己手工和web框架组合在一起工作. 当然和一站式框架相比,稍微多一些的学习成本.换来的是更多的选择甚至更高的性能.
- 一站式就像管家一样,什么不会就问管家,除非管家说我也不会,那你就基本傻眼了.
- 微框架就像个工具人. 而你是项目经理. 它负责做自己份内事.你的能力决定最终结果.
- 一站式框架坑少. 选择入门初期提升快, 但中后期可能会遇到受框架设计思想约束的问题.
- 微框架更开放一些, 有可能坑比较多,入门相对难一些. 但由于微框架对开发者的约束较少. 吃透了以后, 容易达到一种一通百通的状态(微框架的设计思维上基本都是想通的). 中后期在业务处理上会比较得心应手.相对的技术栈可以延伸的更广.
如何选择
django和flask是入门首选.他们共同的特点就是成熟稳定. 两者都已经在生产环境经受过大量考验.性能虽然平庸,但稳如老狗. 业务上基本上是百搭型. github上两者都是51K+的星.根据个人喜爱可以二选一. 2者之间的差别主要是来源于自身的设计思维:
如果你打算长期从事python开发工作,我推荐你用微框架的一站式入门. 虽然开始会多一些磕磕绊绊,但你后来的道路会走的更宽敞. 如果你只是python的web框架轻度用户.无疑学习django见效更快. 当然,你的性格也会影响选择: django的开发者,需要遵守的约定更多一些. 性格上守序一点会比较好(会java的人会有是曾相识的感觉).flask的开发者需要遵守的约定比较少. 语法上也是更贴近于python提倡的简洁直白的风格 . 崇尚真我风格的年轻人可能更容易接受一些.
工作上是框架跟着业务走, 你不能先选择一个框架,让后让业务向框架的技术特点妥协.而是根据当前业务选择最适合的开发框架. 业务的需求是动态变化的.如果你当前的框架满足不了业务发展的需要, 那就选择一个能满足的业务需要的框架和当前的框架配合是使用. 因为你不能期望总有一个框架你满足你的业务发展中的所有需求.微框架因为其低耦合的特性.更容易迎合业务的变化. 这也是我推荐选择flask这种类型的微框架作为入门的原因之一.