fastapi后台任务模块<BackgroundTasks>源码理解

 

 该文档主要对fastapi的后台模块《BackgroundTasks》一些源码的理解, 这样也可以加深理解异步及后台任务处理的理解。

  使用导入例子:

  from fastapi import BackgroundTasks

  

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()


def write_file(data: str):
with open("log.txt", mode="w") as w:
w.write(data)


@app.post("/write-file/")
async def send_notification(data: str, background_tasks: BackgroundTasks):
background_tasks.add_task(write_notification, data)
return {"message": "Notification sent in the background"}

 

 BackgroundTasks源码图:

 

  

从上面使用例子

background_tasks.add_task(write_notification, data)

可看出它是接收了需后台处理的方法,及相关参数传入 background_tasks

 

从源码看:

BackgroundTasks 引用了BackgroundTask 类

BackgroundTask类是初始化接收方法参数,以及写了个__call__的异步调度该方法,还做了是否异步处理的判断,源码如下:
class BackgroundTask:
    def __init__(
        self, func: typing.Callable[P, typing.Any], *args: P.args, **kwargs: P.kwargs
    ) -> None:
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.is_async = is_async_callable(func)

    async def __call__(self) -> None:
        if self.is_async:
            await self.func(*self.args, **self.kwargs)
        else:
            await run_in_threadpool(self.func, *self.args, **self.kwargs)

   

 再看回BackgroundTasks类,我们调度了add_task, 其实就是将接收的需执行方法做了"异步化"后塞进tasks任务列表。源码如下:

def add_task(
    self, func: typing.Callable[P, typing.Any], *args: P.args, **kwargs: P.kwargs
) -> None:
    task = BackgroundTask(func, *args, **kwargs)
    self.tasks.append(task)

  

 最后通过__call__ 函数化调度执行循环该tasks任务列表,通过 async 和 await 异步执行调度任务。

后面我也在思考任务为啥可以类似celery任务在后台执行,对主请求无需上下文阻塞等,我想应该是任务调度里的 async 调度 async化的任务,即可避免阻塞等待结果,可放进后台跑,而如果调度任务非异步调度的也做了适配。

如异步化的源码下图:

上面就是先做是否异步调度的状态判断,如果不是异步的,会放进线程池里进行,这样也可实现类似功能。

 

 

上面就是我对fastapi的BackgroundTasks的源码理解,纯粹是个人理解,可能有些文字描述不是很准确,但应该也能理解吧,哈哈哈~

 

posted @ 2023-08-09 15:45  fengzao  阅读(582)  评论(0编辑  收藏  举报