asyncおよびawaitを使用する
バージョン2.0の新機能。
Flaskがasync
エクストラ(pip install flask[async]
)とともにインストールされている場合、ルート、エラーハンドラー、要求前、要求後、およびティアダウン関数はすべてコルーチン関数になります。 contextvars.ContextVar
が利用可能なPython3.7以降が必要です。 これにより、ビューをasync def
で定義し、await
を使用できます。
@app.route("/get-data")
async def get_data():
data = await async_db_query(...)
return jsonify(data)
プラグ可能なクラスベースのビューは、コルーチンとして実装されるハンドラーもサポートします。 これは、flask.views.View
クラスから継承するビューのdispatch_request()
メソッド、およびflask.views.MethodView
クラスから継承するビューのすべてのHTTPメソッドハンドラーに適用されます。
Python3.8上のWindowsでasync
を使用する
Python 3.8には、Windowsの非同期に関連するバグがあります。 ValueError: set_wakeup_fd only works in main thread
のようなものに遭遇した場合は、Python3.9にアップグレードしてください。
パフォーマンス
非同期関数を実行するには、イベントループが必要です。 Flaskは、WSGIアプリケーションとして、1つのワーカーを使用して1つの要求/応答サイクルを処理します。 リクエストが非同期ビューに入ると、Flaskはスレッドでイベントループを開始し、そこでビュー関数を実行して、結果を返します。
非同期ビューの場合でも、各リクエストは1人のワーカーを拘束します。 利点は、ビュー内で非同期コードを実行して、たとえば、複数の同時データベースクエリ、外部APIへのHTTPリクエストなどを実行できることです。 ただし、アプリケーションが一度に処理できるリクエストの数は同じままです。
非同期は本質的に同期コードよりも高速ではありません。非同期は同時IOバウンドタスクを実行する場合に役立ちますが、CPUバウンドタスクはおそらく改善されません。 従来のFlaskビューは、ほとんどのユースケースに引き続き適していますが、Flaskの非同期サポートにより、以前はネイティブでは不可能だったコードの記述と使用が可能になります。
バックグラウンドタスク
非同期関数は、完了するまでイベントループで実行され、完了するとイベントループが停止します。 これは、非同期関数が完了したときに完了しなかった追加の生成されたタスクがキャンセルされることを意味します。 したがって、たとえばasyncio.create_task
を介してバックグラウンドタスクを生成することはできません。
バックグラウンドタスクを使用する場合は、ビュー関数でタスクを生成するのではなく、タスクキューを使用してバックグラウンド作業をトリガーすることをお勧めします。 そのことを念頭に置いて、 ASGI で説明されているように、ASGIサーバーでFlaskを提供し、asgiref WsgiToAsgiアダプターを利用することで、非同期タスクを生成できます。 これは、アダプターが継続的に実行されるイベントループを作成するときに機能します。
代わりにQuartを使用する場合
Flaskの非同期サポートは、実装方法が原因で、非同期ファーストフレームワークよりもパフォーマンスが低くなります。 主に非同期のコードベースがある場合は、 Quart を検討するのが理にかなっています。 Quartは、WSGIの代わりに ASGI 標準に基づいたFlaskの再実装です。 これにより、複数のワーカープロセスやスレッドを必要とせずに、多数の同時リクエスト、長時間実行されるリクエスト、およびWebSocketを処理できます。
非同期リクエスト処理の多くの利点を得るために、GeventまたはEventletでFlaskを実行することもすでに可能です。 これらのライブラリは、これを実現するために低レベルのPython関数にパッチを適用しますが、async
/ await
およびASGIは、標準の最新のPython機能を使用します。 Flask、Quart、またはその他のものを使用する必要があるかどうかを決定するのは、最終的にはプロジェクトの特定のニーズを理解することです。
拡張
Flaskの非同期サポートより前のFlask拡張機能は、非同期ビューを期待していません。 ビューに機能を追加するためのデコレータを提供する場合、それらは関数を待機しないか、待機できないため、非同期ビューでは機能しない可能性があります。 それらが提供する他の関数も待つことはできず、非同期ビュー内で呼び出された場合はおそらくブロックされます。
拡張機能の作成者は、flask.Flask.ensure_sync()
メソッドを利用して非同期関数をサポートできます。 たとえば、拡張機能がビュー関数デコレータを提供する場合、装飾された関数を呼び出す前にensure_sync
を追加します。
def extension(func):
@wraps(func)
def wrapper(*args, **kwargs):
... # Extension logic
return current_app.ensure_sync(func)(*args, **kwargs)
return wrapper
使用する拡張機能の変更ログをチェックして、非同期サポートが実装されているかどうかを確認するか、機能のリクエストまたはPRを行います。
その他のイベントループ
現時点では、Flaskはasyncio
のみをサポートしています。 flask.Flask.ensure_sync()
をオーバーライドして、別のライブラリを使用するために非同期関数をラップする方法を変更することができます。