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

如何在FastAPI+Uvicorn的HTTP API中并发提供Matplotlib生成的图片?

解决FastAPI+Uvicorn并发下Matplotlib生成图片异常问题

问题根源

Matplotlib的pyplot(即plt)是全局状态式接口,在Uvicorn的并发请求环境(多线程/多进程)中,多个请求会共享同一个全局plt实例,导致图表状态被互相覆盖、干扰,出现空白图或线程相关错误。即使切换到AGG后端,全局状态的冲突依然存在。

解决方案

1. 提前设置非交互式后端

在导入任何Matplotlib模块之前设置AGG后端,确保后端生效:

import matplotlib
matplotlib.use('AGG')  # 必须在导入pyplot或其他matplotlib模块前执行
import matplotlib.pyplot as plt
from io import BytesIO
from PIL import Image
from fastapi import FastAPI, Response

2. 改用面向对象的图表创建方式,避免全局状态

每个请求独立创建Figure和Axes实例,使用实例方法而非全局plt接口操作图表,确保请求间状态完全隔离:

app = FastAPI()

# 假设SIZE_X和SIZE_Y是你定义的常量
SIZE_X = 10
SIZE_Y = 6

@app.get("/generate-plot")
async def generate_plot():
    # 每个请求独立创建fig和ax,不依赖全局plt状态
    fig, ax = plt.subplots(figsize=(SIZE_X, SIZE_Y))
    
    # 为图表添加元素(示例:绘制折线图)
    ax.plot([1, 2, 3, 4], [10, 20, 15, 25])
    ax.set_title("示例图表")
    ax.set_xlabel("X轴")
    ax.set_ylabel("Y轴")
    
    # 使用fig.savefig而非plt.savefig,针对当前实例保存
    fig_buf = BytesIO()
    fig.savefig(fig_buf, format='png')
    fig_buf.seek(0)
    
    # 显式关闭当前图表,释放内存并清除状态
    plt.close(fig)
    
    # 返回图片响应
    return Response(content=fig_buf.getvalue(), media_type="image/png")

3. 关键改进点说明

  • 避免全局plt操作:用fig.savefig替代plt.savefig,确保只操作当前请求的图表实例,不会影响其他请求的全局状态。
  • 及时清理资源:调用plt.close(fig)显式关闭当前图表,避免内存泄漏和残留状态干扰后续请求。
  • 后端设置时机:matplotlib.use('AGG')必须在导入plt或其他Matplotlib模块之前执行,否则后端设置不会生效。

额外优化建议

如果服务并发量较高,可以考虑:

  • 使用Uvicorn的多进程模式(通过--workers参数启动),进一步隔离每个请求的进程空间,避免线程间状态共享。
  • 对高频请求的图表进行缓存,减少重复生成的开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:42:10