首页 > 其他分享 >【FastAPI】解决下载文件预处理时间较长的问题:FastAPI 实现异步任务处理

【FastAPI】解决下载文件预处理时间较长的问题:FastAPI 实现异步任务处理

时间:2024-11-14 16:50:39浏览次数:3  
标签:文件 异步 FastAPI 预处理 file id 下载

解决下载文件预处理时间较长的问题:FastAPI 实现异步任务处理

在开发 Web 应用时,我们经常会遇到需要对文件进行预处理的场景。例如,用户请求下载一个文件之前,需要进行压缩、转换或者数据处理等操作。然而,这些预处理任务往往会花费较长时间,如果我们在后端直接处理这些任务,会导致用户等待很长时间,体验非常糟糕。

那么,我们该如何优化这种场景呢?今天,我们将使用 FastAPI 来实现异步的文件预处理任务,同时允许用户在后台任务完成后下载文件。这将大大提升系统的响应速度和用户体验。

1. 问题的本质

假设你有一个文件下载的功能,但每次下载前,需要进行一些繁重的处理工作,如文件压缩、数据计算或者图像处理等。这些任务可能需要几秒甚至几分钟的时间。如果在处理期间,用户一直无法得到反馈或者下载文件,体验将非常差。

为了避免阻塞主线程并给用户一个良好的反馈,我们可以将这些长时间的任务放到后台处理,而让用户继续正常使用应用。当任务完成后,我们再通知用户文件已准备好,并提供下载链接。

2. 使用 FastAPI 实现异步任务

FastAPI 是一个现代、快速(高性能)的 web 框架,它支持异步编程,并能快速构建 API。我们可以利用 FastAPI 的 后台任务BackgroundTasks)来处理文件的预处理工作,这样就不会阻塞用户的请求。

2.1 安装依赖

首先,你需要安装 FastAPIUvicorn(FastAPI 推荐的 ASGI 服务器)。

pip install fastapi uvicorn
2.2 代码实现

我们将实现一个简单的文件预处理和下载功能,假设文件预处理任务需要一些时间(比如 10 秒钟),并且用户可以在后台任务完成后下载文件。

import os
import time
from fastapi import FastAPI, BackgroundTasks, HTTPException
from fastapi.responses import FileResponse

app = FastAPI()

# 假设这里是文件存储路径
DOWNLOAD_FOLDER = "./files"

# 模拟一个长时间的预处理任务
def long_preprocess_task(file_id: str):
    time.sleep(10)  # 假设任务需要10秒来完成
    
    # 模拟生成一个文件(可以是压缩文件、文本文件等)
    file_content = f"This is the preprocessed file for {file_id}."
    file_path = os.path.join(DOWNLOAD_FOLDER, f"{file_id}.txt")
    
    # 确保目录存在
    os.makedirs(os.path.dirname(file_path), exist_ok=True)
    
    # 写入文件
    with open(file_path, "w") as f:
        f.write(file_content)
    
    print(f"File {file_id} has been processed and saved at {file_path}.")

@app.get("/download/{file_id}")
async def download_file(file_id: str, background_tasks: BackgroundTasks):
    # 启动后台任务进行文件预处理
    background_tasks.add_task(long_preprocess_task, file_id)
    
    # 返回文件准备中的提示信息
    return {"message": f"File {file_id} is being prepared. Please check again shortly."}

@app.get("/files/{file_id}")
async def get_file(file_id: str):
    file_path = os.path.join(DOWNLOAD_FOLDER, f"{file_id}.txt")
    
    # 检查文件是否存在
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="File not found or still processing.")
    
    # 返回文件响应,供用户下载
    return FileResponse(file_path, media_type='application/octet-stream', filename=f"{file_id}.txt")

3. 代码详解

3.1 long_preprocess_task

这个函数模拟了一个需要 10 秒钟才能完成的预处理任务。你可以根据实际需求,将其替换为任何长时间运行的任务,如文件压缩、图片处理等。

任务完成后,我们将文件保存到 ./files/ 目录,并确保目录存在。如果目录不存在,os.makedirs() 会自动创建。

3.2 GET /download/{file_id}

当用户请求下载文件时,/download/{file_id} 路由会被触发。这个路由将启动一个后台任务 long_preprocess_task,并返回一个提示消息,告知用户文件正在准备中。由于任务是异步进行的,用户可以继续执行其他操作,而无需等待文件预处理完成。

3.3 GET /files/{file_id}

这个路由用于返回实际的文件。用户可以通过 GET /files/{file_id} 来下载已经准备好的文件。我们使用 FileResponse 来返回文件,并设置 media_typeapplication/octet-stream,这将提示浏览器下载文件。

如果文件还没有准备好,系统会返回一个 404 错误,提示文件不存在或仍在处理中。

4. 启动和测试应用

  1. 将上述代码保存为 app.py,然后使用 Uvicorn 启动 FastAPI 应用:
uvicorn app:app --reload
  1. 使用浏览器或者 Postman 测试以下 API:

    • 启动文件预处理

      GET http://localhost:8000/download/myfile
      

      响应:

      {
        "message": "File myfile is being prepared. Please check again shortly."
      }
      
    • 查询文件下载链接

      GET http://localhost:8000/files/myfile
      

      如果文件已经准备好,浏览器会开始下载该文件。如果文件仍在处理中,会返回如下错误信息:

      {
        "detail": "File not found or still processing."
      }
      

5. 完整流程总结

  1. 用户请求下载:当用户请求下载文件时,后端会启动一个后台任务进行文件预处理。
  2. 后台任务处理:文件预处理任务会在后台独立执行,不会阻塞主线程。任务完成后,文件会被保存到服务器的指定目录。
  3. 用户下载文件:用户可以通过访问 GET /files/{file_id} 来下载文件。如果文件已准备好,系统会返回文件内容;如果文件尚未准备好,则返回 404 错误。

6. 优化和扩展

这个简单的例子已经能够满足基本的需求,但你可以进一步扩展和优化:

  • 文件状态追踪:使用数据库或者缓存(如 Redis)来跟踪文件处理状态,提供更精确的进度反馈。
  • 错误处理:增加更多的错误处理逻辑,例如文件处理失败时的回滚操作,或者任务超时的处理。
  • 结合 Celery:如果文件处理任务更加复杂或者需要高并发,结合 Celery 等任务队列可以提供更强大的任务调度和管理功能。

7. 结语

通过 FastAPI 的 后台任务(BackgroundTasks),我们可以轻松地将长时间运行的任务(如文件预处理)异步化,从而避免阻塞主线程,提高系统的响应速度和用户体验。希望这个简单的示例能够帮助你更好地理解如何在 FastAPI 中实现异步任务和文件下载功能,提升应用的性能和可用性!

标签:文件,异步,FastAPI,预处理,file,id,下载
From: https://blog.csdn.net/h1773655323/article/details/143775646

相关文章

  • Java8 CompletableFuture异步任务
    无返回值调用importjava.util.concurrent.CompletableFuture;publicclassTestDemo{publicstaticvoidmain(String[]args){System.out.println("进入主线程=============");CompletableFuture.runAsync(()->getNum());System.......
  • 深入理解Spring框架中的@Async注解实现异步任务
    目录1.引言2.环境准备3.启用异步支持4.创建异步任务5.调用异步任务6.运行应用7.使用@Async需要注意的地方8.结论在现代Web应用中,异步任务的执行变得越来越重要。Spring框架提供了强大的@Async注解,可以帮助开发者轻松实现异步任务。本文将详细介绍如何在Sprin......
  • Fastapi使用redis
    异步版本rediss.pyfromfastapiimportFastAPI,Depends,APIRouterimportredis.asyncioasaioredisimportuvicornfromcontextlibimportasynccontextmanagerapp=FastAPI()#Redis连接池配置REDIS_URL="redis://192.168.252.128:6379/0"@asyncconte......
  • python-27-Python ORM系列之彻底搞明白ORM概念,对ORM进行封装结合FastAPI实现数据库的
    python-27-PythonORM系列之彻底搞明白ORM概念,对ORM进行封装结合FastAPI实现数据库的增删改查,联表查询等接口一.简介在Python基础系列ORM部分为大家介绍了如何搭建MySQL数据和MySQL一些访问配置,同时也介绍了pymysql库的封装来实现对数据库的增删改查功能,但是截止以上都没......
  • LiTS 数据集预处理(二) 肝脏肿瘤图像分割
    继续上次要完成的目标:肝脏肿瘤分离在上次的工作LiTS数据集预处理(一)肝脏肿瘤图像分割,我们对CT图像进行了切片处理,并生成了相应的标签(Label)。需要注意的是,CT图像和标签之间是一一对应的,数量自然也是相同的。掩膜处理在原本的代码中,有两行用于处理掩膜的代码被注释掉了:#......
  • LiTS 数据集预处理(一) 肝脏肿瘤图像分割
    前言最近在学习Unet等家族做肝脏肿瘤分割,肝脏肿瘤公开数据集有出名的(全球人都在研究的)LITS数据集,从网上下载下来的时候,格式是nii文件。因为我是学习的2D模型训练,所以我需要对nii格式文件进行切片,经过研究学习网上几份代码,发现其中还有有点讲究的,所以想写篇文章分享介绍一......
  • 【C Language Program】预处理指令
    学习目标:掌握C语言的预处理指令以及使用学习步骤:预处理指令的概括预处理指令的使用总结主要内容:预处理指令的概括含义指令导入模块#include宏定义#define#undef条件编译#if#else#elif#endif条件定义#ifdef#ifndef预处理指令的使用#include#include用于在......
  • 同步异步,阻塞非阻塞
    同步异步,阻塞非阻塞区别: 同步:调用者发出请求后,一直等待被调用者返回结果或通知,才进行下一步操作。 异步:调用者发出请求后,不等待被调用者返回结果或通知,就进行下一步操作。阻塞:调用者发出请求后,被调用者不返回结果或通知,调用者就一直等待,不能进行其他操作。 非阻塞:调用者发出请......
  • 【Nginx学习】深入 Nginx:4大步骤揭秘 Nginx 请求的多阶段异步处理
    ......
  • (21-3)基于深度强化学习的量化交易策略(OpenAI Baselines +FinRL+DRL+PyPortfolioOpt):数据
    21.6 数据预处理数据预处理是训练高质量机器学习模型的关键步骤,在这一步需要检查缺失数据并进行特征工程,以将数据转换为适合模型训练的状态。本项目的数据预处理江湾城以下工作:添加技术指标:在实际交易中,需要考虑各种信息,例如历史股价、当前持仓股票、技术指标等。本文演示......