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

yappi在FastAPI+Uvicorn多线程环境下无法捕获非主线程数据

FastAPI+Uvicorn下yappi无法捕获业务线程调用的解决方案

核心原因

Uvicorn默认采用多进程模式启动服务,主线程中启动的yappi追踪不会被fork出的子进程继承,而业务代码实际运行在这些子进程的工作线程中,导致追踪不到自定义函数调用。即使手动指定多线程模式,若yappi未在工作线程初始化,也无法捕获数据。


解决方法

方法1:代码内集成(单进程模式)

强制Uvicorn以单进程启动,并利用FastAPI的启动钩子在工作线程内初始化yappi:

import yappi
from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.on_event("startup")
def init_tracing():
    # 可选设置时钟类型:wall( wall-clock时间)或cpu(CPU时间)
    yappi.set_clock_type("wall")
    # 开启线程+协程追踪(若使用异步路由必须开协程追踪)
    yappi.start(trace_threads=True, trace_coroutines=True)

@app.on_event("shutdown")
def stop_tracing():
    yappi.stop()
    # 输出函数调用统计
    print("\n=== 函数调用统计 ===")
    yappi.get_func_stats().print_all()
    # 输出线程统计
    print("\n=== 线程统计 ===")
    yappi.get_thread_stats().print_all()

# 你的业务路由
@app.get("/api/test")
async def test_business():
    # 模拟业务逻辑
    result = 0
    for i in range(100000):
        result += i
    return {"result": result}

if __name__ == "__main__":
    # 强制单进程启动Uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000, workers=1)

方法2:代码内集成(多进程模式)

若必须用多进程,需开启Uvicorn的preload参数,并在子进程初始化时启动yappi:

import yappi
from fastapi import FastAPI
import uvicorn
import os

app = FastAPI()

def init_yappi():
    yappi.set_clock_type("wall")
    yappi.start(trace_threads=True, trace_coroutines=True)

# 检测当前进程是否是Uvicorn fork出的子进程
if os.getpid() != os.getppid():
    init_yappi()

@app.on_event("shutdown")
def stop_tracing():
    yappi.stop()
    yappi.get_func_stats().print_all()

@app.get("/api/test")
async def test_business():
    result = 0
    for i in range(100000):
        result += i
    return {"result": result}

if __name__ == "__main__":
    # 多进程+预加载模式
    uvicorn.run(app, host="0.0.0.0", port=8000, workers=2, preload=True)

方法3:CLI命令启动

使用yappi CLI时,需配合Uvicorn的单进程+预加载参数,确保追踪覆盖工作线程:

yappi -c wall uvicorn server.main:app --workers 1 --preload

关键注意点

  • 若你的FastAPI路由使用异步函数,必须开启trace_coroutines=True,否则yappi无法捕获协程内的函数调用。
  • 不要仅在主线程启动yappi,必须在业务代码运行的线程/进程内完成追踪初始化。
  • Uvicorn的preload参数会让代码在fork子进程前加载,确保子进程能继承初始化逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:25:27