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

FastAPI多并发请求处理逻辑及癌症预测应用相关疑问

FastAPI多用户并发处理及请求响应匹配问题解答

一、同时调用/uploadfile/路由的处理逻辑

FastAPI基于ASGI协议,默认搭配Uvicorn服务器运行,通过异步事件循环处理并发请求:

  • 每个用户的上传请求会被封装为独立协程任务,在事件循环中调度执行。
  • 你的代码中,shutil.copyfileobj是同步IO操作,在异步函数中执行会阻塞事件循环,导致其他请求等待。建议用asyncio.to_thread将文件写入操作放到线程池,避免阻塞主事件循环。
  • 严重问题:代码中的global current_filename是全局变量,多用户并发上传时会被后请求的用户覆盖,完全失去作用还会引发数据混乱,建议直接删除。
  • 额外风险:直接使用用户上传的原文件名保存文件,若两个用户上传同名文件,后上传的会覆盖先上传的,导致前一个用户的预测请求拿到错误文件。

二、同时调用/predict/路由的处理及响应匹配逻辑

并发处理

  • 每个预测请求同样会作为独立协程在事件循环中处理,但预测过程(模型加载、推理)是同步计算,会阻塞事件循环。鉴于单预测耗时2分钟,建议用asyncio.to_thread或Celery等任务队列将预测任务异步化,放到后台执行,避免阻塞主服务。
  • 每次预测都调用utils.get_models_list()加载模型会重复占用内存、增加耗时,建议在应用启动时一次性加载模型,全局复用。

响应如何匹配对应用户

FastAPI(及所有HTTP服务器)无需认证即可匹配请求与响应,核心依赖HTTP协议的请求-响应模型:

  • 客户端发起请求时,会与服务器建立TCP连接(HTTP/1.1默认复用连接,但每个请求有独立的请求头/体)。
  • 服务器处理每个请求时,会维护独立的请求上下文(如客户端连接信息、请求标识),处理完成后通过对应的TCP连接将响应返回给发起请求的客户端。
  • 你的前端代码中,每个用户的浏览器会独立发起/predict/请求,服务器会将该请求的预测结果返回给发起它的浏览器,不会混淆。但要注意:若两个用户上传同名文件,预测时会拿到同一个文件的结果,这是业务逻辑问题,而非服务器响应匹配问题。

代码优化建议

  1. 文件上传优化:

    • 生成唯一文件名避免覆盖:
      import uuid
      from fastapi import UploadFile, File
      import asyncio
      import shutil
      from pathlib import Path
      
      @app.post("/uploadfile/")
      async def create_upload_file(file: UploadFile = File(...)):
          # 生成唯一文件名,避免冲突
          unique_filename = f"{uuid.uuid4().hex}_{file.filename}"
          path = Path(__file__).parents[1] / "saved_images" / unique_filename
          try:
              # 把同步IO放到线程池,不阻塞事件循环
              await asyncio.to_thread(shutil.copyfileobj, file.file, path.open("wb"))
          except Exception as e:
              print("Error: ", e)
          # 返回唯一文件名给前端
          return {"filename": unique_filename}
      
  2. 预测路由优化:

    • 提前加载模型,复用内存:
      # 应用启动时一次性加载模型
      models = utils.get_models_list()
      
      @app.get("/predict/")
      async def predict(filename: str):
          path = Path(__file__).parents[1] / "saved_images" / filename
          dataset_test = DatasetTest(df_single_image, 'test', 'test', transform=transforms_test)
          image = dataset_test[0]
          # 预测任务放到线程池,避免阻塞事件循环
          prediction, probs = await asyncio.to_thread(utils.predict_single_image, image, models)
          return {"Probs": probs, "Prediction": prediction}
      
  3. 前端逻辑优化:

    • 上传后获取后端返回的唯一文件名,避免同名文件冲突:
      const PredictButton = () => {
          const selectedFile = useContext(FileContext);
          const [pred, setPred] = useState(null);
      
          const handleUpload = async () => {
              const formData = new FormData();
              formData.append("file", selectedFile, selectedFile.name);
      
              const requestOptions = {
                  method: 'POST',
                  body: formData,
              };
              const resp = await fetch('http://localhost:8000/uploadfile', requestOptions);
              const data = await resp.json();
              return data.filename; // 获取后端返回的唯一文件名
          }
          const handlePredict = async () => {
              const uniqueFilename = await handleUpload();
              const resp = await fetch(`http://localhost:8000/predict/?filename=${uniqueFilename}`);
              const data = await resp.json();
              setPred(data["Prediction"]);
          }
          return (
              <div className="predict-button">
                  <button className="predict-button-button" onClick={handlePredict}>Predict!</button>
                  <div className="pred">
                      {pred===null ? null : (pred === 1 ? <div className="detected">Prediction: Cancer Detected</div> : <div className="no-detected">Prediction: No cancer Detected</div>)}
                  </div>
              </div>
          )
      }
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 10:26:01