摘要
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 | 串行执行 | 严格按添加顺序 | 任务有依赖(如按顺序更新数据库) |