Zenn
📘

FastAPIの非同期処理と並行処理の使い分け

2025/03/28に公開

業務でFastAPIのパフォーマンスチューニングに触れる機会があり、非同期処理(async def)と並行処理(def)の違いってなんだっけ?みたいな感じになったので、備忘録で残します。

はじめに(おさらい)

1. 同期処理とは?

同期処理は、タスクを一つずつ順番に処理する方法です。一つのタスクが終わるまで次のタスクは待機します。

# 同期処理の例
def make_banana_smoothie():
    peel_banana()    # 完了するまで待つ
    cut_banana()     # 完了するまで待つ
    blend_banana()   # 完了するまで待つ
    return "スムージー完成!"

同期処理のメリット・デメリット

メリット:

  • シンプルで分かりやすい
  • デバッグが容易

デメリット:

  • I/O(アイオー) 待ち時間が無駄になる
  • 処理時間が長くなりがち

2. 並列処理とは?

並列処理は、複数のタスクを文字通り同時に実行する方法です。複数のCPUコアを使って、異なるタスクを同時に処理します。

# multiprocessingを使った並列処理
import multiprocessing

def process_data_chunk(chunk):
    # 計算集約型の処理
    result = heavy_calculation(chunk)
    return result

if __name__ == '__main__':
    # 大きなデータを分割
    data_chunks = split_data(big_data, 4)
    
    # プロセスプールを作成(CPUコア数に合わせる)
    with multiprocessing.Pool(processes=4) as pool:
        # 複数プロセスで同時に計算
        results = pool.map(process_data_chunk, data_chunks)
    
    # 結果を結合
    final_result = combine_results(results)

並列処理のメリット・デメリット

メリット:

  • 複数のCPUコアを同時に活用できる
  • プロセス間は独立しているため、単一のプロセスが失敗しても全体に影響しにくい

デメリット:

  • プロセス間通信のオーバーヘッドがある
  • メモリ使用量が増加する
  • データ共有がしづらい(しないほうがいい)
    • 各プロセスは独立したメモリ空間を持つため、データを共有するには仕組みが必要

3. 並行処理とは?

並行処理は、複数のタスクを切り替えながら処理する方法です。Python では主にスレッドや子プロセスを使います。

# スレッドを使った並行処理
import threading

def process_bananas():
    thread1 = threading.Thread(target=peel_banana)
    thread2 = threading.Thread(target=cut_pineapple)
    
    thread1.start()
    thread2.start()
    
    thread1.join()
    thread2.join()

並行処理のメリット・デメリット

メリット:

  • I/O 待ち時間を有効活用できる
  • メモリ空間を共有するため、データ共有が容易
  • スレッド切り替えのコストが比較的小さい

デメリット:

  • リソース競合が発生する可能性がある
  • デバッグがしづらい

4. 非同期処理とは?

非同期処理は、I/O 待ち時間に別の作業を行う方法です。Python では asyncio を使います。

# 非同期処理の例
import asyncio

async def process_fruit():
    task1 = asyncio.create_task(async_peel_banana())
    task2 = asyncio.create_task(async_cut_pineapple())
    
    await task1
    await task2

async def main():
    await process_fruit()

asyncio.run(main())

非同期処理のメリット・デメリット

メリット:

  • I/O 待ち時間を最大限に活用
  • 単一スレッドでリソース競合を回避

デメリット:

  • すべてのライブラリが非同期対応しているわけではない

5. 料理でのイメージ

同期処理

一人の料理人が一つの料理を最初から最後まで順番に作業。次の工程には前の工程が完了後にしか進めない。(シングルスレッド)

並列処理

複数の料理人が別々の料理を同時に完全独立して調理。お互いの作業に影響なし。(マルチプロセス)

並行処理

複数の料理人による流れ作業。材料係→調理係→盛付け係と分担し連携。全員が同時に別の工程で作業していますが、連携して一つの料理を作り上げる。(マルチスレッド)

非同期処理

一人の料理人が効率的に作業。肉を焼いている間に野菜を切るなど、待ち時間を活用して複数のタスクを切り替えながら進める。(イベントループ)

(本題)FastAPIにおける非同期処理と並行処理の使い分け

結論

  • async def → 非同期処理
  • def → 並行処理(マルチスレッド)
  • 基本的には def を推奨します

処理の仕組み

FastAPIは内部的にマルチスレッドを使って実行するため、複数のリクエストが同時に来ても、マルチスレッドで処理可能な数までは並行して処理できます。

一方、非同期処理はシングルスレッドで動作します。このため、awaitが付いていない処理を実行している間は、他のリクエストの処理がブロックされてしまいます。使用するライブラリやメソッドがawait対応してるのが必須です。

公式の推奨事項

・await を使って呼び出すサードパーティライブラリを使用している場合: path operation関数は async def で宣言してください。
・データベース、API、ファイルシステムなどと通信し、awaitをサポートしていないサードパーティライブラリ(現在のほとんどのデータベースライブラリが該当)を使用している場合: 普通に def を使ってpath operation関数を宣言してください。
・アプリケーションが他の何とも通信せず、応答を待つ必要がない場合: async def を使ってください。
・よく分からない場合は、通常の def を使ってください。

引用元: https://fastapi.tiangolo.com/ja/async/

サンプル

OpenAIの画像分析結果を出力して保存するケース

非同期クライアント(AsyncOpenAI)がawaitをサポートしているため、async defを使用しています。これによりOpenAIからの応答を待つ間に他の処理を行うことができ、出力を早くすることができます。

from fastapi import FastAPI
from openai import AsyncOpenAI
import os

app = FastAPI()
client = AsyncOpenAI(api_key=os.environ.get("OPENAI_API_KEY"))

@app.post("/analyze-image")
async def analyze_image(image_url: str):
    # OpenAIの非同期クライアントを使用して画像分析
    response = await client.chat.completions.create(
        model="gpt-4-vision-preview",
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "この画像を分析してください"},
                    {"type": "image_url", "image_url": {"url": image_url}}
                ]
            }
        ],
        max_tokens=300
    )
    
    analysis_result = response.choices[0].message.content
    
    # 結果を返す
    return {"analysis": analysis_result}

まとめ

無闇に時間のかかりうる処理を非同期処理にするのではなく、使用するライブラリが非同期(async)対応しているか確認した方がいい。非同期対応しているならasync defで定義し、対応していない場合はdefで定義する方がベターです

ヘッドウォータース

Discussion

ログインするとコメントできます