升級 Flask 到 Quart 獲得 3 倍性能提升

lambce 7年前發布 | 38K 次閱讀 Flask Quart asyncio Python開發

升級 Flask 到 Quart 獲得 3 倍性能提升

簡評:將你的 Flask 應用程序升級到 Quart 應用程序,輕松獲得 3 倍的性能提升,本文將用一個簡單的 demo 來告訴大家如何去做。

自從 Flask 在 8 年前發布以來,Python 發生了很大變化,特別是引入了 asyncio。asyncio 允許開發像 uvloop 和 asyncpg 這樣的庫來提高性能,可惜要 Flask 集成 asyncio 或這些庫不是一件簡單的事情。 然而,Flask-API 可以通過 Quart 框架與 asyncio 一起使用。

Quart 提供了一個簡單的過渡機制使得 Flask 應用程序可以使用 asyncio,因為它們共享 Flask-API,這意味著現有的 Flask 應用程序可以在 Quartz 應用程序中進行很少的改進,然后就可以使用這些新的庫來產生使用 Flask 無法實現的性能改進。

本文詳細介紹了典型的生產環境的 CRUD 應用程序從 Flask 到 Quart 的轉換,并展示了典型生產部署的性能改進。

tl;dr

將這個 Flask-pyscopg2 應用程序升級到 Quart-asyncpg 應用程序可以提高 3 倍的性能,而不需要對代碼進行重大的重寫或調整。

升級 Flask 到 Quart 獲得 3 倍性能提升

應用程序

對于這個比較,我將使用一個簡單的只提供一個 RESTful 接口的應用程序,這是微服務架構中的常見用例,并提供了一個非常簡單的代碼庫進行比較。

該應用程序有由三個路由組成的兩個藍圖。這些路由有

  • 單個資源: GET /films/<int:id>/
  • 所有資源: GET /films/
  • 新資源: POST /reviews/

源代碼可以在 https:// github.com/pgjones/fast er_than_flask_article 找到,有兩個 commit ,一個 Flask 版本和一個 Quart 版本。

從 Flask 到 Quart

從 Flask 改用 Quart 很容易,只需要一點的改變,特別是 from flask 改為 from quart,函數變成異步函數。完整的 diff 是,

def add_review():
    data = request.get_json()
    ...

變成

async def add_review():
    data = await request.get_json()
    ...

從 psycopg2 到 asyncpg

從 psycopg2 改用 asyncpg 比較麻煩,因為兩者有不同的用法。為了簡化 diff,在 Flask 應用程序中使用了 PoolWrapper,來使用與 asyncpg 相同的 API 為上下文管理的 psycopg2 連接,即 with pool.acquire() as connection: ,這使得 asyncpg 可以把 with 改為 async with。

除了連接之外,asyncpg 和 psycopg2 在 cursor 使用、事務、執行參數和查詢格式上也有所不同。這些大多是不同的約定,完整的 diff 

部署

將 Flask 應用程序直接暴露給生產環境不太可能擴展,并不代表典型的生產環境。這是因為Flask 本身一次只能處理一個請求。相反,WSGI 服務器通常與某種異步 worker 結合使用,例如 帶 eventlet 的Gunicorn。

Quart 也可以用 Gunicorn 部署,它允許使用相同的命令來運行 Flask 和 Quart 應用程序:

$ gunicorn --config gunicorn.py 'run:create_app()'

性能測試是在 Gunicorn 后面運行的 Flask 和 Quart 應用程序進行的。

數據庫

除了添加一個簡單的 review 表之外,Postgresql 示例數據庫 為應用程序提供一些用于 CRUD的數據。

CREATE TABLE review (
    film_id INTEGER REFERENCES film(film_id), 
    rating INTEGER
);

性能測試

使用 wrk 來測量應用程序的性能。配置為使用20個連接來匹配數據庫連接池大小(這應該確保最高的吞吐量,而 20 是我用過的典型值)。

測試 GET 請求的命令是

$ wrk --connections 20 --duration 5m http://localhost:5000/${PATH}/

測試 POST 請求的命令是

$ wrk --connections 20 --duration 5m --script post.lua http://localhost:5000/${PATH}/

( post.lua 

測試系統

Postgres (9.5.10),wrk (4.0.0),Python (3.6.3),asyncpg (0.13.0),Flask (0.12.2),Gunicorn (19.7.1),psycopg2 (2.7.3.2), Quart (0.3.1)。全部運行在一臺 AWS c4.large 機器上。

結果

Route           | Requests per second | Average Latency [ms]  |
                |   Flask  |   Quart  |   Flask   |   Quart   |
---------------------------------------------------------------
GET /films/995/ |   330.22 |  1160.27 |     60.55 |     17.23 |
GET /films/     |    99.39 |   194.58 |    201.14 |    102.76 |
POST /reviews/  |   324.49 |  1113.81 |     61.60 |     18.22 |

請注意,Quart 服務器的平均等待時間減少了 2 至 3.5 倍,每秒的請求數量增加了 2 至 3.5 倍。

結論

Flask 應用程序升級到 Quart 應用程序是相當簡單的,因為共享 API ,所以主要工作就是在正確的位置寫 async 和 await 。 然而,如果使用 SQLAlchemy(或其他 ORM),則從psycopg2 到 asyncpg 的改變會比較復雜,并且可能會很麻煩。

這個 demo 應用程序的性能顯著提高,這個改進主要是由于 Quart 使用了 asyncpg 和 uvloop,據估計,僅 Quart 就能提供 1.5 倍的提升。

總之,從 Flask-psycopg2 應用程序升級到 Quart-asyncpg 應用程序的比較的簡單,并提供了非常合理的性能改進。這可能會擴展到其他基于 asyncio 的庫,這意味著將 Flask 應用程序轉換到 asyncio 生態系統,Quart 只需要很小的工作量。

 

 

來自:https://zhuanlan.zhihu.com/p/31578547

 

 本文由用戶 lambce 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!