FastAPI は async def と通常の def の両方をパス操作でサポートしています。パフォーマンスに影響するため、非ブロッキング I/O を await できるときは async def を、ブロッキング(同期)操作を呼び出すコードのときは通常の を使用してください。
def@app.get("/async")
async def async_endpoint():
data = await fetch_from_api() # await non-blocking I/O — efficient
return data
@app.get("/sync")
def sync_endpoint():
data = blocking_db_call() # ordinary blocking code
return data
async def → runs on the main event loop. Efficient ONLY if you await non-blocking calls.
⚠️ A BLOCKING call inside async def blocks the WHOLE event loop → kills concurrency!
def → FastAPI runs it in a THREAD POOL, so blocking code doesn't block the event loop.
Safe for synchronous/blocking libraries.
# ✅ async def — when you can await async libraries (httpx, async DB drivers)
async def get_user():
async with httpx.AsyncClient() as c:
return await c.get(url)
# ✅ plain def — when using SYNCHRONOUS/blocking libraries (requests, sync ORM)
def get_user():
return requests.get(url).json() # blocking → FastAPI runs it in a thread
# ❌ THE DANGEROUS MISTAKE — blocking call inside async def
async def bad():
return requests.get(url).json() # blocks the event loop! Use `def` or an async client
重要な法則:async def にブロッキング呼び出しを決して入れてはいけません — イベントループをブロックしてコンカレンシーを破壊します。async ライブラリを await で使用するか、プレーンな def を使用してください(FastAPI はスレッドプール内で安全に実行します)。
async def と def の間で正しく選択することは、API のパフォーマンスとコンカレンシーに直接影響し、誤った選択は一般的で深刻なミスです。
重要な洞察は、async def は非ブロッキング操作を await するときだけ有益ということです。ブロッキング呼び出し(同期的な requests ライブラリやブロッキングデータベースドライバなど)を async def の中に入れると、イベントループ全体をブロックし、すべてのコンカレント要求を凍結させて、async の目的を失わせます。
逆に、FastAPI はプレーンな def エンドポイントをスレッドプール内で巧妙に実行するため、同期的/ブロッキングコードはそこで安全です。
この法則を理解することが重要です。async def は本当に async なライブラリで使用し、ブロッキングコードにはプレーンな def を使用し、ブロッキング呼び出しを async def に混在させない。これはパフォーマンスの良い FastAPI エンドポイントを書くために必須であり、イベントループがブロックされた状態ですべてのリクエストを誤って直列化してしまう微妙だが壊滅的なミスを避けるために必要です。