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

Python:Popen stdout=PIPE无法读取进度条,如何实时获取?

问题

我尝试通过UDP Socket传输控制台程序的进度条,实现远程展示任务完成状态,但遇到了问题:subprocess的stdout.PIPE能读取普通print输出,却读不到进度条内容,写入文件或UDP时显示空白。我推测是进度条输出没有以\n结尾,导致没被导入stdout.PIPE——但即使移除普通print语句,进度条仍能在控制台正常显示。

用tqdm库复现问题的代码如下:

sample_process.py

from time import sleep
from tqdm import tqdm
for i in range(10):
    print(i)
    
for i in tqdm(range(10)):
    sleep(0.5)

client.py

import socket
from subprocess import Popen, PIPE, CalledProcessError

serverAddressPort   = ("127.0.0.1", 20001)
bufferSize          = 1024

UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
cmd = ['python', 'sample_process.py']

with Popen(cmd, stdout=PIPE, bufsize=0, universal_newlines=True) as p:
    for line in p.stdout:
        print(line, end='')
        UDPClientSocket.sendto(line.encode(), serverAddressPort)

if p.returncode != 0:
    raise CalledProcessError(p.returncode, p.args)

server.py

import socket

UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
UDPServerSocket.bind(("127.0.0.1", 20001))
while(True):
    bytesAddressPair = UDPServerSocket.recvfrom(1024)
    message = bytesAddressPair[0]
    print(message.decode())

另外,执行print(p.stdout.read())时,必须等进程结束才会输出内容。请问在Windows 11、Python 3.9.13环境下,有没有办法实时读取进度条?

解决方案

针对Windows环境下tqdm进度条无法被subprocess实时读取的问题,可通过以下几种方式解决:

1. 强制tqdm输出到stdout并禁用缓冲

tqdm默认会检测输出环境,当检测到非终端(比如PIPE)时可能会调整行为。修改sample_process.py中的tqdm调用,强制指定输出到stdout并关闭缓冲:

from time import sleep
from tqdm import tqdm
import sys

for i in range(10):
    print(i)
    
# 强制输出到stdout,确保非终端环境下正常输出
for i in tqdm(range(10), file=sys.stdout, disable=False, dynamic_ncols=True):
    sleep(0.5)

同时保持client.py中的bufsize=0(无缓冲)配置,确保实时读取字节流。

2. 逐字符读取stdout而非按行读取

进度条使用回车\r而非换行\n刷新,按行读取会因缺少换行符而阻塞。修改client.py的读取逻辑,改为逐字节读取:

import socket
from subprocess import Popen, PIPE, CalledProcessError

serverAddressPort   = ("127.0.0.1", 20001)
bufferSize          = 1024

UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
cmd = ['python', 'sample_process.py']

with Popen(cmd, stdout=PIPE, bufsize=0, universal_newlines=False) as p:
    while True:
        # 每次读取1字节,捕获进度条的回车刷新信号
        chunk = p.stdout.read(1)
        if not chunk:
            break
        UDPClientSocket.sendto(chunk, serverAddressPort)
        print(chunk.decode(), end='')

if p.returncode != 0:
    raise CalledProcessError(p.returncode, p.args)

这种方式能实时获取进度条的每一次更新,包括\r字符,实现远程同步展示。

3. 修改tqdm输出格式为换行更新

如果不需要进度条在控制台原地刷新,可修改tqdm的bar_format,让每次进度更新都输出新行:

for i in tqdm(range(10), bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt}\n'):
    sleep(0.5)

此时进度条每次更新都会生成带\n的输出,client.py的按行读取逻辑就能正常工作,无需修改读取代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 06:37:38