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

Flask流式数据无法实时更新:仅停服务后才显示数据求助

问题分析与解决方案

这问题我太熟了,核心原因是Flask默认的单线程运行模式在搞鬼,再加上你的代码里对/api/stream的GET和POST请求没做区分,直接导致了请求阻塞。

为什么会出现这种情况?

  1. Flask默认是单线程、单进程运行的,同一时间只能处理一个请求。当你发送POST请求到/api/stream时,这个请求会进入event_stream的无限循环,一直占用着唯一的线程。
  2. 当你打开/api/output时,浏览器会发起GET请求到/api/stream建立SSE连接,但这个请求被前面的POST请求死死堵住,根本得不到响应。
  3. 只有当你停止Flask服务,那个卡住的POST请求被终止,所有缓存的SSE数据才会一次性发送给浏览器,所以你看到停服务后才弹出所有数字。

怎么解决?

我给你三个递进的解决方案,按需选择:

1. 开启Flask的多线程模式

最简单的临时解决办法,启动Flask时加上threaded=True参数,让它能同时处理多个请求:

if __name__ == '__main__':
    application.run(threaded=True)

这样POST请求和SSE的GET请求就不会互相阻塞了,浏览器能实时收到SSE数据。

2. 区分GET和POST请求的处理逻辑

你的POST请求明显不是来获取SSE流的,应该把/api/stream的GET和POST分开处理,避免POST请求进入无限循环:

# 专门处理SSE的GET请求
@application.route('/api/stream', methods=['GET'])
def stream():
    def event_stream():
        n = 0
        while True:
            yield "data: %s\n\n" % n
            n += 1
            time.sleep(1)
    return Response(event_stream(), mimetype='text/event-stream')

# 专门处理POST请求
@application.route('/api/stream', methods=['POST'])
def handle_stream_post():
    # 这里写你实际要处理的POST逻辑,比如接收参数、触发任务等
    return "POST request processed"

这样POST请求处理完就会返回,不会占用线程,SSE连接也能正常建立并实时推送数据。

3. 用异步任务处理耗时操作(进阶)

如果你的POST请求是要触发一个耗时任务,然后通过SSE推送任务进度,那单线程/多线程可能不够用,建议用后台线程或者异步任务队列(比如Celery)来处理任务,避免阻塞请求线程。举个简单的后台线程例子:

from threading import Thread
from flask import request

# 存储客户端的SSE连接(简单实现,实际可用Redis等存储)
clients = []

@application.route('/api/stream', methods=['GET'])
def stream():
    def event_stream():
        # 将当前连接加入客户端列表
        clients.append(event_stream)
        try:
            n = 0
            while True:
                yield "data: %s\n\n" % n
                n += 1
                time.sleep(1)
        finally:
            # 连接关闭时移除客户端
            clients.remove(event_stream)

    return Response(event_stream(), mimetype='text/event-stream')

@application.route('/api/stream', methods=['POST'])
def trigger_task():
    def background_task():
        # 模拟耗时任务并推送进度
        for i in range(10):
            time.sleep(1)
            # 给所有客户端推送进度
            for client in clients:
                client(f"data: Task progress: {i*10}%\n\n")
        # 任务完成推送结束信号
        for client in clients:
            client("data: Task completed\n\n")

    # 启动后台线程执行任务
    Thread(target=background_task).start()
    return "Task started"

这种方式更适合实际的进度推送场景,不会阻塞主线程,也能正确处理多个客户端的SSE连接。


内容的提问来源于stack exchange,提问作者Daniel Koczuła

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:11:56