web-dev-qa-db-ja.com

GunicornとGeventでFlaskを実行しているときのリクエストで非ブロッキングリクエストを行う

My Flaskアプリケーションはリクエストを受信し、処理を行ってから、応答に5秒かかる遅い外部エンドポイントにリクエストを送信します。GeventでGunicornを実行すると、処理できるようになりますこれらの低速なリクエストの多くが同時に表示されます。ビューがブロックされないように、次の例を変更するにはどうすればよいですか?

import requests

@app.route('/do', methods = ['POST'])
def do():
    result = requests.get('slow api')
    return result.content
gunicorn server:app -k gevent -w 4
19
JLTChiu

Flaskアプリケーションをgunicornでデプロイしている場合は、すでにブロックされていません。クライアントがビューの1つからの応答を待機している場合、別のクライアントが同じ複数のリクエストを同時に処理する複数のワーカーが存在します。これを機能させるためにコードを変更する必要はありません。これは、ほとんどすべてのFlaskデプロイメントオプションに当てはまります。

12
sytech

最初に少し背景を説明すると、ブロックソケットはデフォルトのソケットです。アプリの読み取りを開始すると、データが実際に読み取られるか、接続が切断されるまでスレッドは制御を取り戻しません。こうやって python-requests、デフォルトで動作します。非ブロッキング読み取りを提供するgrequestsと呼ばれるスピンオフがあります。

主な機械的な違いは、送信、受信、接続、受け入れが何もせずに戻ることができることです。 (もちろん)選択肢はたくさんあります。リターンコードとエラーコードを確認し、通常は気が狂います。あなたが私を信じないなら、いつかそれを試してください

ソース: https://docs.python.org/2/howto/sockets.html

また、次のようにも言います。

最速のソケットコードがノンブロッキングソケットを使用し、それらを多重化することを選択していることは間違いありません。 CPUに負担をかけることなく、LAN接続を飽和させるものをまとめることができます。問題は、この方法で作成されたアプリは他に何もできないことです。常にバイトをシャッフルする準備ができている必要があります。

アプリが実際にそれ以上のことをすることになっていると仮定すると、スレッド化が最適なソリューションです

しかし、ビューに独自のスレッドを生成させることで、ビューに非常に多くの複雑さを追加したいのですか。特に、gunicornが 非同期ワーカー ?の場合

使用可能な非同期ワーカーは、Greenletに基づいています(EventletおよびGevent経由)。 Greenletsは、Python用の協調型マルチスレッドの実装です。一般に、アプリケーションはこれらのワーカークラスを変更せずに使用できる必要があります。

そして

非同期ワーカーを必要とする動作の例:長いブロッキング呼び出しを行うアプリケーション(つまり、外部Webサービス)

長い話を短くするために、何も変更しないでください!そのままにしてください。変更を行う場合は、キャッシングを導入してください。 Cache-control python-requests開発者が推奨する拡張機能の使用を検討してください。

6
e4c5

grequestsを使用できます。要求が行われている間、他のグリーンレットを実行できます。 requestsライブラリーと互換性があり、requests.Responseオブジェクト。使用方法は次のとおりです。

import grequests

@app.route('/do', methods = ['POST'])
def do():
    result = grequests.map([grequests.get('slow api')])
    return result[0].content

編集:テストを追加しましたが、gunicornのgeventワーカーが初期化されたときにすでにモンキーパッチを実行しているため、grequestsで時間が改善されないことがわかりました: https://github.com/benoitc/gunicorn/blob /master/gunicorn/workers/ggevent.py#L65

1
jerry