FastAPI Docker容器中如何实时转发stdout输出?
Docker容器中无法实时转发子进程stdout输出的问题解决
问题描述
开发了一个基于Whisper AI模型的音频转写API,通过WebSocket实时获取子进程stdout输出以实现前端进度条展示。核心WebSocket代码如下:
@app.websocket("/ws/transcribe") async def transcribe_websocker(websocket: WebSocket): await websocket.accept() process = subprocess.Popen(['python', 'ai.py'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, shell=False) while True: line = process.stdout.readline() if not line: break # Encode and send the line to the WebSocket client encoded_line = line.encode('utf-8') print(encoded_line) await websocket.send_text(encoded_line) # Close the process and the WebSocket connection process.stdout.close() process.wait() await websocket.close()
Windows本地用uvicorn main:app --reload运行时,能实时推送进度;但部署到Docker容器后,所有输出仅在子进程执行完毕后一次性发送,无法实时更新进度。使用的Dockerfile如下:
FROM python:3.10-slim WORKDIR /python-docker RUN apt-get update && apt-get install git -y RUN pip3 install fastapi RUN pip3 install "uvicorn[standard]" RUN pip3 install -U git+https://github.com/jianfch/stable-ts.git RUN apt-get install -y ffmpeg RUN pip3 install moviepy RUN pip3 install streaming_form_data RUN pip3 install websockets COPY . . #COPYING MODELS COPY base.pt /root/.cache/whisper/base.pt EXPOSE 8000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
解决方案
问题根源是Python在非交互式环境下默认启用块缓冲:Windows本地为交互式终端,stdout是行缓冲;Docker容器环境默认是块缓冲,导致输出被缓存直到进程结束才释放。可通过以下方式解决:
1. 启动子进程时强制禁用缓冲
修改subprocess.Popen调用,给Python解释器添加-u参数(禁用stdout/stderr缓冲):
process = subprocess.Popen( ['python', '-u', 'ai.py'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, shell=False )
也可以通过bufsize=0参数直接设置无缓冲,但-u参数作用于子进程Python解释器,兼容性更好。
2. 在子进程代码中手动刷新输出
如果无法修改启动参数,在ai.py的输出语句中添加flush=True,强制立即写入stdout:
import sys # 输出进度时添加刷新操作 print("转写进度:50%", flush=True)
3. 全局设置Python无缓冲环境变量
在Dockerfile中添加环境变量,让所有Python进程默认禁用缓冲:
ENV PYTHONUNBUFFERED=1
将上述代码添加到WORKDIR之后的位置即可。
内容的提问来源于stack exchange,提问作者Moiz Hassan
相关产品推荐
相关产品推荐

