寫在前面:
本文的數據涉及到我面試時遇到過的問題,大概一次 http 請求到收到響應需要多少時間。這個問題在實際工作中與框架有比較大的關系,因此特別就框架的性能做了一次分析。
這里使用 2016 年 6 月 9 日的報告數據: Python's Web Framework Benchmarks。本文僅關注目前最常用的三大 Python 框架:Django、 Flask 以及 Tornado。
報告主要比較三點:
- JSON:序列化一個對象,并返回一個 json。
- 遠程性能:從遠程服務器上返回 http response 的時間
- 數據庫性能:使用 ORM(對象關系映射)從數據庫獲取數據,并渲染到模板上的時間
最基本的 json 測試:Django 與 Flask 占優
單純在本地測試 json 的序列化,Django 完成一次 json 序列化的平均時間 42.52 毫秒,每秒請求量 4762 次。Flask 在此項測試中,與 Django 的比較不相上下,Flask 平均時間 43.33 毫秒,每秒請求量 4630 次。Tornado 完成 json 序列化的平均時間高達 77.51 毫秒,是所有框架中耗時最長的,每秒請求數是 2578 次,也是低于 Django 與 Flask 的水準。這僅僅說明框架在本地處理 json 的速度。框架還涉及 http request/response 以及數據庫的讀寫,后面還需要綜合來分析框架的性能。
處理遠程 http 請求的能力:Tornado 占絕對優勢
從這項測試開始,Tornado 的強悍開始顯現。Tornado 完成 http 請求的平均時間是 1.04 秒,而 Flask 是 3.34 秒,Django 是 3.48 秒,http 響應速度 Tornado 比 Flask 以及 Django 快三倍。
值得注意是,如果綜合考慮 http 相應速度以及json 處理速度,如果把兩項指標的平均時間相加:Tornado 耗時 1114.48 毫秒,Flask 是 3387.60 毫秒,Django 是 3519.88 毫秒。
Tornado 的好成績得益于其自帶的異步特性,而 Django 與 Flask 是同步框架,在處理請求時性能受限。但是實際使用中,一般是 Django/Flask + Celery + Redis/Memchaned/RabbitMQ 的模式,由此帶上了異步處理的能力。
數據庫與模板處理性能:Tornado 與 Flask 旗鼓相當
Django 飽受詬病的地方就是 Django ORM 確實很慢,加上模板處理時間,Django 的平均時間 2904.04 毫秒,每秒處理請求量 42.9 次。然而 Django 的大部分功能是建立在其 Django ORM 基礎上,比如 models, admin, forms 甚至第三方框架 django-rest-framework。Django 的開發效率與維護非常棒,然而 Django ORM 深度綁定了該框架,如果你需要把 Django ORM 換成其它輪子,那么也意味著 Django 的諸多優秀特性將從此告別。
Flask 事實上的 ORM 是 SQLAlchemy,根據董偉明的估計,SQLAlchemy 比 MySQLdb 的耗時多 5% 左右,所以是性能相當不錯的數據庫 ORM。得益于 SQLAlchemy 的優異性能,Flask 的每秒處理請求數為 123 次,平均處理時間 1440.24 秒,與 Tornado 性能相當。
Tornado 的每秒處理請求數為 143 次,平均處理時間 1344.69 秒。對于數據庫與模板的處理,Tornado 與 Flask 不相上下。
結論
- Django:Python 界最全能的 web 開發框架,battery-include 各種功能完備,可維護性和開發速度一級棒。常有人說 Django 慢,其實主要慢在 Django ORM 與數據庫的交互上,所以是否選用 Django,取決于項目對數據庫交互的要求以及各種優化。而對于 Django 的同步特性導致吞吐量小的問題,其實可以通過 Celery 等解決,倒不是一個根本問題。Django 的項目代表:Instagram,Guardian。
- Tornado:天生異步,性能強悍是 Tornado 的名片,然而 Tornado 相比 Django 是較為原始的框架,諸多內容需要自己去處理。當然,隨著項目越來越大,框架能夠提供的功能占比越來越小,更多的內容需要團隊自己去實現,而大項目往往需要性能的保證,這時候 Tornado 就是比較好的選擇。Tornado項目代表:知乎。
- Flask:微框架的典范,號稱 Python 代碼寫得最好的項目之一。Flask 的靈活性,也是雙刃劍:能用好 Flask 的,可以做成 Pinterest,用不好就是災難(顯然對任何框架都是這樣)。Flask 雖然是微框架,但是也可以做成規模化的 Flask。加上 Flask 可以自由選擇自己的數據庫交互組件(通常是 Flask-SQLAlchemy),而且加上 celery +redis 等異步特性以后,Flask 的性能相對 Tornado 也不逞多讓,也許Flask 的靈活性可能是某些團隊更需要的。
總結,蘿卜白菜各有所愛,然而機器的效率(程序的性能)與程序員的效率(可維護性、開發速度)是一對矛盾。選擇什么樣的架構組合,取決于產品的特性以及團隊的能力。