fastapi之中,background_tasks的学习笔记

128 阅读2分钟

摘要

background_tasks 的具体实现(常见于 FastAPI/Starlette 或自定义工具),默认情况下并非「队列排序执行」,而是并发执行,但存在细节差异:

1. 若为 FastAPI/Starlette 自带的 BackgroundTasks

这是最常见的场景,其核心行为是:

  • 无队列排序,默认并发执行:添加的多个任务会交给事件循环(如 asyncio)调度,任务启动顺序不严格按 add_task 调用顺序,且会「同时」运行(本质是 asyncio 的协作式并发,并非多线程)。
  • 依赖事件循环空闲:背景任务会在当前请求处理完成后、事件循环无其他高优先级任务时才开始执行,且不会阻塞主线程。
  • 示例
    from fastapi import BackgroundTasks
    
    async def task1():
        print("Task 1 start")
        await asyncio.sleep(2)  # 模拟耗时操作
        print("Task 1 end")
    
    async def task2():
        print("Task 2 start")
        await asyncio.sleep(1)
        print("Task 2 end")
    
    # 调用时
    background_tasks.add_task(task1)
    background_tasks.add_task(task2)
    # 实际输出可能是:Task1 start → Task2 start → Task2 end → Task1 end(并发)
    

2. 若需「队列排序执行」(串行)

若业务需要任务按添加顺序逐个执行(前一个完成后再执行下一个),需手动实现队列逻辑,例如用 asyncio.Queue 控制:

import asyncio
from fastapi import BackgroundTasks

# 全局任务队列(确保单例)
task_queue = asyncio.Queue()

# 队列消费者(持续从队列取任务执行)
async def queue_worker():
    while True:
        task = await task_queue.get()  # 阻塞等待任务
        await task()  # 串行执行任务
        task_queue.task_done()  # 标记任务完成

# 启动消费者(需在应用启动时执行一次,如 FastAPI 的 startup 事件)
@app.on_event("startup")
async def startup_worker():
    asyncio.create_task(queue_worker())

# 封装添加任务的函数(将任务放入队列,而非直接执行)
async def add_task_to_queue(task):
    await task_queue.put(task)

# 调用方式
background_tasks.add_task(add_task_to_queue, task1)  # 先加入队列
background_tasks.add_task(add_task_to_queue, task2)  # 后加入队列
# 此时会严格按顺序执行:Task1 完成 → Task2 开始

关键总结

场景执行方式顺序性适用场景
FastAPI 原生 BackgroundTasks并发执行无序(调度决定)无依赖的独立背景任务(如日志、通知)
自定义 Queue + Worker串行执行严格按添加顺序任务有依赖(如按顺序更新数据库)