FastAPI异步后台任务会阻止其他请求吗? [英] fastapi asynchronous background tasks blocks other requests?
本文介绍了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
'srun_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屋!
查看全文