You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Uvicorn自动重载时无法终止子线程问题求助

解决Uvicorn重载时后台线程残留的问题

你的问题核心是:启动的后台线程默认是非守护线程,且没有优雅停止的逻辑,导致Uvicorn重载时旧进程无法正常退出,线程持续运行。下面是具体的解决思路:

1. 标记线程为守护线程

默认threading.Thread的daemon参数为False,非守护线程会强制阻止主进程退出。创建线程时显式设置daemon=True,主进程结束时系统会自动终止这类线程:

import threading
import time

def update_loop():
    while True:
        print("my print from my thread")
        time.sleep(5)

# 启动守护线程
threading.Thread(target=update_loop, daemon=True).start()

⚠️ 注意:如果线程内有需要收尾的操作(比如写入文件、关闭数据库连接),这个方法会直接终止线程,可能导致数据丢失,建议结合下面的优雅停止方案。

2. 给线程添加优雅停止信号

用threading.Event作为线程的停止标志,在线程循环中检测该标志,收到停止信号后安全退出。同时利用FastAPI的shutdown事件触发停止逻辑:

from fastapi import FastAPI
import threading
import time

app = FastAPI()
# 线程安全的停止信号
stop_event = threading.Event()

def update_loop():
    while not stop_event.is_set():
        print("my print from my thread")
        time.sleep(5)
    # 这里添加收尾操作,比如保存数据、释放资源
    print("后台线程已优雅退出")

# 应用启动时启动线程
@app.on_event("startup")
def start_background_task():
    threading.Thread(target=update_loop).start()

# 应用关闭时触发停止信号
@app.on_event("shutdown")
def stop_background_task():
    stop_event.set()

这样Uvicorn触发shutdown流程时,会通知线程停止,线程完成当前循环后安全退出,不会残留。

3. 不要在模块级别启动线程

如果你的线程是直接写在api.py的模块最外层(比如导入模块就启动),Uvicorn重载时会重新导入模块,但旧进程的线程仍在运行。必须把线程启动逻辑放在FastAPI的startup事件中,确保只有应用实例启动时才创建线程,且关闭时能通过shutdown事件清理。

4. 生产环境建议

开发环境用--reload没问题,但生产环境不要依赖这个机制。生产环境可以用Uvicorn的多进程模式,或者用专门的任务调度工具管理后台定时任务,避免手动创建线程带来的进程管理问题。

内容的提问来源于stack exchange,提问作者Jules Civel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 09:23:12