首先:
- 沒有專用的服務器
- 沒有測試專用的代碼片段
- 沒有牛人背書
這只是一個簡單的對比: 用一臺普通的機器,以盡量相同的方式分別部署不同Web框架編寫的一段簡單程序.然后使用壓力測試程序run一下,做個chart出來.直觀的反應一下. .python的常用框架性能之間的差別.較真的杠精現(xiàn)在就可以出門左轉(zhuǎn)了.
先要介紹一下我的測試環(huán)境: acer的商務機,具體配置是酷睿8,8g,1t的5400轉(zhuǎn)機械硬盤, 操作系統(tǒng)是ubuntu 18.04 desktop
本次使用的代碼特別簡單,所以因為個人能力不濟造成性能下降的可能性比較小,哈哈.本次測試的是一些常用的python的Web開發(fā)框架.下面有請選手登場:
- Django 不用說,最早進入中國的python web框架之一, 一站式結構, 文檔齊全, 功能強大.用戶眾多,入坑首選之一
- Flask 知名度和Django在伯仲之間的python web框架,和相對重型的Django不同,flask標榜自己的輕量級, 做個單純的web框架,只負責路由和視圖部分,其他的交給插件部分(flask眾多的插件也是亮點之一).入坑首選之二
- AioHttp 一個異步的web框架,包含服務端和客戶端,推薦python 3.5+, 視圖函數(shù)是異步寫法.也是因為異步,所以性能出色.
- Sanic 也是異步類flask的web框架,無需插件即支持websocket,因為是類flask框架,所以從flask 轉(zhuǎn)過來的話無論學習還是維護成本都是極低的.性能自己說也是非常高的.在國外有大量的生產(chǎn)環(huán)境案例. 插件/中間件很豐富.
- Tornado 是一個facebook開源的異步框架,自己的文檔說速度相當快,國內(nèi)也有很多人這么說,我不怕劇透,其實他的性能從4.2時代就已經(jīng)很落伍了.而且由于他的異步機制是自己搞的一套.很多東西寫法都很獨特.學習成本較高.所以,本人是不推薦學習的.也沒任何優(yōu)勢而已,這里把他拉出來就是為了襯托同行.
- Bottle 一個超簡潔的輕量級web框架.(5年之前)以性能著稱.同步模式.國外國內(nèi)都不算應用廣.比flask更簡潔,但是插件也比較少.
- Falcon 這個國內(nèi)用的不多,但是國外用戶還是很多的.以安全穩(wěn)定著稱(就是所謂的線程安全那種,你懂的),自說是性能和安全的最佳平衡.有很多生產(chǎn)環(huán)境的案例.主要是用于提供接口服務. 語法稍微繁瑣一點.
- Vibora 一個很新的異步模式的類flask的web框架,flask開發(fā)者友好(要搶flask的飯碗?),性能也是變態(tài)的好.個人覺得不錯.(畢竟類flask的框架,對插件的依賴是可有可無的)
很多人都知道Python語言的代碼,以運行緩慢著稱(我這是引用眾數(shù)的觀點.不抬杠),所以很多人詬病Python的web框架運行緩慢.不過,個人的觀點是: 實務中, 特別當你不是那么大的分布式的部署的時候,性能瓶頸往往是壓在數(shù)據(jù)庫而不是web框架上.你可以根據(jù)自己的網(wǎng)站/業(yè)務的訪問量計算一下你選中的Web框架是否能滿足你的需求?
測試代碼就是各自的文檔中的hello world代碼.部署上能用gunicorn的就用,有些部署比較特殊的框架那沒辦法,總是,盡量減少部署方式上的差異(python的web框架,部署方式對性能的影響還是非常大的).
測試方式使用siege做并發(fā)壓力測試,從50客戶端開始,每次測試遞增50個客戶端,一直到最后1000個客戶端,每次5000個事務請求. 每個框架做400批次壓力測試.最后的結果清洗后做個統(tǒng)計,使用pygal生成圖表. x軸是客戶端數(shù)量,y軸是每秒處理多少事務(TPS),所有的測試結果都是100%完成.
測試結果
Django

Flask

Bottle

Falcon

從這里開始,都是異步的框架了
Tornado

Sanic

AioHttp

Vibora

全家福

個人總結:
- 無論同步還是異步模式,所有的框架在低并發(fā)(50客戶端以內(nèi))性能都是出奇的好.如果使用QPS的換算公式的話.你會發(fā)現(xiàn),如果一般性類的網(wǎng)站(企業(yè)門戶,個人博客之類),速度上完全沒問題.
- 并發(fā)能力上來說,Django和Flask難兄難弟日常墊底兒.但這并不影響他們的廣泛應用.而且,即使是他們的墊底性能,也能在1000客戶端的情況下維持每秒1000上下的TPS.坦白的說,這算不上高性能,但是滿足絕大多數(shù)站點(尤其是創(chuàng)業(yè)初期的產(chǎn)品原型)的需求是沒問題了.
- 同步工作模式和異步工作模式相比,并發(fā)能力上全面落后挨打.甚至被秒殺.但是,異步工作模式在代碼書寫上是有要求的(有些coder常說的一步異步,處處異步并不是沒有道理的).并且異步提升的是單位時間的處理能力.在你的服務器崩潰之前,異步工作模式并不會提供更高的處理能力.
- Tornado 成也性能,敗也性能.在異步的時代,tornado以較高學習成本,捉急的性能,讓成為拍在沙灘上的前浪.至少現(xiàn)在.不要說tornado的性能高什么的了.
- Vibora 性能確實變態(tài). 即使1000客戶端,也能維持超過1萬的TPS.值得關注一下.
以上是空載的數(shù)據(jù),如果加上本地的數(shù)據(jù)庫負載(原子操作).所有的框架沒有任何差別.瓶頸都在數(shù)據(jù)庫IO上.
python的web框架多如牛毛(遠不像國內(nèi)的翻來覆去django,flask,tornado三大件).特點也是千差萬別.基本上越新的框架越有后發(fā)的優(yōu)勢,我會在工作之余,做一些相關的對比工作.
代碼片段(Hello World):
測試代碼引自官方文檔,未做任何優(yōu)化.
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開發(fā)框架,抱歉這個真沒有.每個框架都有其存在的價值或者意義,盡管在某些方面看起來有些過時.和某些一兩個框架獨大的語言不同.python語言的框架是一種百花齊放百家爭鳴的狀態(tài). 不過大體來說, python的web開發(fā)框架分2大類:
- 全能型的一站式框架
- 自助式的微框架
一站式框架
一站式框架提供了從路由,ctos,模板渲染,中間件, web-socket支持和orm等你想到的想不到的各種功能.有什么問題,看文檔就行了. 語法的一致性好. 新需求導致的學習成本曲線平緩. 不太容易掉坑里. 一站式框架的典型代表是 Django.(發(fā)音類似: 姜戈,前面的d不發(fā)音)
微框架
微框架就是那種只提供基本功能的框架.在python中,這種提供單一功能的微框架忒多. 比如Flask僅僅提供了路由,藍圖之類的基本功能.(Flask模板還是借助jinja2來實現(xiàn)的,當然你也可以使用其他模板). 其他的功能,都需要你借助插件或者庫來完成.比如說ORM方面,sqlalchemy, peewee, pony這些orm框架僅僅提供orm功能.你可以接觸插件或者自己手工和web框架組合在一起工作. 當然和一站式框架相比,稍微多一些的學習成本.換來的是更多的選擇甚至更高的性能.
- 一站式就像管家一樣,什么不會就問管家,除非管家說我也不會,那你就基本傻眼了.
- 微框架就像個工具人. 而你是項目經(jīng)理. 它負責做自己份內(nèi)事.你的能力決定最終結果.
- 一站式框架坑少. 選擇入門初期提升快, 但中后期可能會遇到受框架設計思想約束的問題.
- 微框架更開放一些, 有可能坑比較多,入門相對難一些. 但由于微框架對開發(fā)者的約束較少. 吃透了以后, 容易達到一種一通百通的狀態(tài)(微框架的設計思維上基本都是想通的). 中后期在業(yè)務處理上會比較得心應手.相對的技術??梢匝由斓母鼜V.
如何選擇
django和flask是入門首選.他們共同的特點就是成熟穩(wěn)定. 兩者都已經(jīng)在生產(chǎn)環(huán)境經(jīng)受過大量考驗.性能雖然平庸,但穩(wěn)如老狗. 業(yè)務上基本上是百搭型. github上兩者都是51K+的星.根據(jù)個人喜愛可以二選一. 2者之間的差別主要是來源于自身的設計思維:
如果你打算長期從事python開發(fā)工作,我推薦你用微框架的一站式入門. 雖然開始會多一些磕磕絆絆,但你后來的道路會走的更寬敞. 如果你只是python的web框架輕度用戶.無疑學習django見效更快. 當然,你的性格也會影響選擇: django的開發(fā)者,需要遵守的約定更多一些. 性格上守序一點會比較好(會java的人會有是曾相識的感覺).flask的開發(fā)者需要遵守的約定比較少. 語法上也是更貼近于python提倡的簡潔直白的風格 . 崇尚真我風格的年輕人可能更容易接受一些.
工作上是框架跟著業(yè)務走, 你不能先選擇一個框架,讓后讓業(yè)務向框架的技術特點妥協(xié).而是根據(jù)當前業(yè)務選擇最適合的開發(fā)框架. 業(yè)務的需求是動態(tài)變化的.如果你當前的框架滿足不了業(yè)務發(fā)展的需要, 那就選擇一個能滿足的業(yè)務需要的框架和當前的框架配合是使用. 因為你不能期望總有一個框架你滿足你的業(yè)務發(fā)展中的所有需求.微框架因為其低耦合的特性.更容易迎合業(yè)務的變化. 這也是我推薦選擇flask這種類型的微框架作為入門的原因之一.