Flask で非同期処理を扱う(async/await の制限と回避策)
Flask 2.0 から async/await がサポートされたが、制限や落とし穴がある。Flask で非同期処理を扱う際の注意点と回避策を解説する。
Flask 2.0 の async サポート
Flask 2.0 以降では、ビュー関数を async def で定義できる。
from flask import Flask
app = Flask(__name__)
@app.route('/async')
async def async_view():
await some_async_operation()
return 'Done'ただし、Flask 自体は WSGI フレームワークであり、真の非同期フレームワーク(FastAPI など)とは異なる。
制限: 同期的なコンテキスト
Flask のリクエストコンテキストは同期的に設計されている。非同期タスクを別スレッドやコルーチンで実行すると、コンテキストが伝播しない。
import asyncio
@app.route('/problem')
async def problem():
# 危険: 別タスクではコンテキストが存在しない
task = asyncio.create_task(background_work())
await task
return 'Done'
async def background_work():
# RuntimeError: Working outside of application context
print(current_app.name)回避策 1: copy_current_request_context
Flask が提供するデコレータでコンテキストをコピーできる。
from flask import copy_current_request_context
@app.route('/safe')
async def safe():
@copy_current_request_context
async def background_work():
# コンテキストがコピーされている
return current_app.name
result = await background_work()
return result回避策 2: 必要な値を先に取得
コンテキストに依存するデータを先に取り出してから非同期処理に渡す。
@app.route('/extract')
async def extract():
# 先に必要な値を取得
config_value = current_app.config['API_KEY']
user_id = g.user.id
# 非同期処理には値だけを渡す
result = await process_async(config_value, user_id)
return result非同期 WSGI サーバー
Flask で async を最大限活用するには、非同期対応の WSGI サーバーを使う。
pip install asgiref
gunicorn -k uvicorn.workers.UvicornWorker app:appまたは Hypercorn を使う。
pip install hypercorn
hypercorn app:appFlask vs 真の非同期フレームワーク
| Flask | WSGI ベース、async は後付けサポート |
| FastAPI | ASGI ネイティブ、非同期が第一級市民 |
| Quart | Flask 互換の ASGI フレームワーク |
大量の I/O バウンドな処理が必要なら、Quart への移行も検討すべきである。Quart は Flask とほぼ同じ API を持つ。
from quart import Quart
app = Quart(__name__)
@app.route('/async')
async def async_view():
# Quart では自然に非同期が使える
result = await async_db_query()
return resultFlask での非同期は可能だが、制限を理解した上で使うこと。本格的な非同期が必要なら、ASGI フレームワークを検討すべきである。



