FastAPI异步后台任务会阻止其他请求吗? [英] fastapi asynchronous background tasks blocks other requests?

查看:0
本文介绍了FastAPI异步后台任务会阻止其他请求吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在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,这意味着fast api(或者更确切地说,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)
    
    • 或直接使用asyncios's run_in_executor(run_in_threadpool暗中使用):
      import asyncio
      async def task(data):
          otherdata = await db.fetch("some sql")
          loop = asyncio.get_running_loop()
          newdata = await loop.run_in_executor(None, lambda: somelongcomputation(data, otherdata))
          await db.execute("some sql", newdata)
      
      您甚至可以将concurrent.futures.ProcessPoolExecutor作为第一个参数传递给run_in_threadpool,以便在单独的进程中运行它。
  • 自己派生一个单独的线程/进程。例如使用concurrent.futures

  • 使用更重的东西,比如芹菜。(在Fastapi文档here中也有提及)。

这篇关于FastAPI异步后台任务会阻止其他请求吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆