1. ホーム
  2. python

[解決済み] fastapiの非同期バックグラウンドタスクは、他のリクエストをブロックしますか?

2022-02-28 10:16:36

質問

fastapiで簡単なバックグラウンドタスクを実行したいのですが、データベースにダンプする前に何らかの計算を伴います。しかし、その計算は、それ以上のリクエストを受け取ることをブロックするでしょう。

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()
db = Database()

async def task(data):
    otherdata = await db.fetch("some sql")
    newdata = somelongcomputation(data,otherdata) # this blocks other requests
    await db.execute("some sql",newdata)
   


@app.post("/profile")
async def profile(data: Data, background_tasks: BackgroundTasks):
    background_tasks.add_task(task, data)
    return {}

この問題を解決する最善の方法は何でしょうか?

解決方法は?

あなたの task は次のように定義されています。 async ということは、fastapi(というかstarlette)はasyncioのイベントループの中で実行されることになります。 そして somelongcomputation は同期(つまり IO を待たずに計算を行う)なので、イベントループが実行されている間はブロックされます。

これを解決する方法はいくつかありますね。

  • より多くのワーカーを使用する(例 uvicorn main:app --workers 4 ). これにより、最大で4つの somelongcomputation を並列に表示します。

  • にならないようにタスクを書き換えてください。 async (として定義します。 def task(data): ... など)。そうすると、starletteは別スレッドで実行します。

  • 使用方法 fastapi.concurrency.run_in_threadpool も別スレッドで実行されます。このように

    from fastapi.concurrency import run_in_threadpool
    async def task(data):
        otherdata = await db.fetch("some sql")
        newdata = await run_in_threadpool(lambda: somelongcomputation(data, otherdata))
        await db.execute("some sql", newdata)
    
    
  • 別のスレッド/プロセスを自分で起動する。例えば concurrent.futures .

  • celeryのようなもっと強引なものを使ってください。(fastapiのドキュメントにも記載されています。 ここで ).