每天一个Python小技巧:Flask流式响应+g对象实战:高效处理大数据请求(二)
在Web开发中,处理大文件下载或实时数据推送时,传统的一次性响应往往会占用大量内存。本文将介绍如何使用Flask的Response对象结合g对象实现高效的流式输出。
·
引言
大家好,今天继续我们的"每天一个Python小技巧"系列。在Web开发中,处理大文件下载或实时数据推送时,传统的一次性响应往往会占用大量内存。本文将介绍如何使用Flask的Response对象结合g对象实现高效的流式输出。
一、什么是流式响应?
流式响应(Streaming Response)允许服务器将数据分块(chunk)发送给客户端,而不是等待所有数据准备好后一次性发送。这种方式特别适合:
大文件下载(如视频、日志文件)
实时数据推送(如大模型的推理过程)
长时间运行的任务进度报告
二、基础流式响应实现
我们先看一个最简单的流式响应示例:
from flask import Flask, Response
import time
app = Flask(__name__)
def generate_data():
"""模拟数据生成器"""
for i in range(5):
yield f"数据块 {i}\n" # yield是关键!
time.sleep(1) # 模拟数据处理延迟
@app.route('/basic_stream', methods=['POST'])
def basic_stream():
return Response(generate_data(), content_type='text/plain')
if __name__ == "__main__":
# 运行 Flask 应用
app.run(host='0.0.0.0', port=5007, debug=True)
"""
curl -X POST 127.0.0.1:5007/basic_stream
数据块 0
数据块 1
数据块 2
数据块 3
数据块 4
"""
调用这个接口(curl -X POST 127.0.0.1:5007/basic_stream),你会看到数据是逐块显示的,而不是一次性加载完成。
三、结合g对象增强流式响应
g对象是Flask提供的请求上下文全局变量,非常适合存储请求级别的数据。结合流式响应可以做到:
from flask import Flask, Response, g, stream_with_context
import time
import uuid
from datetime import datetime
app = Flask(__name__)
@app.before_request
def init_request():
"""请求预处理:初始化g对象数据"""
g.request_id = str(uuid.uuid4())[:8] # 生成简短请求ID
g.start_time = datetime.now() # 记录请求开始时间
def generate_enhanced_data():
"""增强版数据生成器,使用g对象数据"""
yield f"请求 {g.request_id} 开始于 {g.start_time}\n"
for i in range(1, 6):
elapsed = (datetime.now() - g.start_time).total_seconds()
yield f"区块 {i} | 已耗时: {elapsed:.2f}秒\n"
time.sleep(0.8) # 模拟处理延迟
yield f"\n请求 {g.request_id} 处理完成!"
@app.route('/enhanced_stream', methods=['POST'])
def enhanced_stream():
"""注意必须使用stream_with_context包装生成器"""
return Response(
stream_with_context(generate_enhanced_data()),
content_type='text/plain'
)
if __name__ == "__main__":
# 运行 Flask 应用
app.run(host='0.0.0.0', port=5007, debug=True)
"""
curl -X POST 127.0.0.1:5007/enhanced_stream
请求 89ea7fa2 开始于 2025-04-25 09:26:12.200373
区块 1 | 已耗时: 0.00秒
区块 2 | 已耗时: 0.80秒
区块 3 | 已耗时: 1.61秒
区块 4 | 已耗时: 2.41秒
区块 5 | 已耗时: 3.21秒
请求 89ea7fa2 处理完成!
"""
关键点说明:
- stream_with_context 必须使用,否则生成器内无法访问g对象
- yield 是Python生成器关键语法
- g对象自动保证线程安全,每个请求独立
四、常见问题解答
Q:为什么我的生成器内无法访问g对象?
A:必须使用stream_with_context()包装生成器函数
Q:流式响应会影响性能吗?
A:对于大数据量,流式响应会显著降低内存占用,但可能增加少量网络开销
Q:如何中断长时间运行的流式响应?
A:客户端断开连接时,生成器会自动停止,也可以通过信号量机制主动停止
结语
Flask的流式响应结合g对象,为我们处理大文件、实时数据等场景提供了优雅的解决方案。记住关键点:
- 使用yield而非return
- 必须用stream_with_context包装
- g对象存储请求级别数据
更多推荐
所有评论(0)