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

为何QProcess无法通过readyRead信号捕获Python子进程的stdout?

问题描述

执行以下C++代码调用Whisper工具:

QProcess p_Whisper;
p_Whisper.setArguments( QStringList()
<< "--model"                      << "medium.en"
<< "--output_dir"                 << d_Hidden.absolutePath()
<< "--task"                       << "transcribe"
<< "--language"                   << "en"
<< "--condition_on_previous_text" << "False"
<< "--no_speech_threshold"        << "0.5"
<< "--logprob_threshold"          << "None"
<< "--threads"                    << "8"
<< "--fp16"                       << "False"
<< "--verbose"                    << "True"
<< f.fileName()
);
p_Whisper.setProgram("/home/anon/.local/bin/whisper");

在Shell中执行对应命令时,能正常输出转录内容:

/home/anon/.local/bin/whisper --model tiny.en --output_dir /home/anon/Music/AF/.transcripts --task transcribe --language en --condition_on_previous_text False --no_speech_threshold 0.5 --logprob_threshold None --threads 8 "/home/anon/Music/AF/CORONAVIRUS PANDEMIC - New Cases in France, Chicago- Virus Spreading RAPIDLY _ America First Ep. 53..-OoFCDcxBbvQ.m4a"  
/home/anon/.local/lib/python3.10/site-packages/whisper/transcribe.py:78: UserWarning: FP16 is not supported on CPU; using FP32 instead
  warnings.warn("FP16 is not supported on CPU; using FP32 instead")
[00:00.000 --> 00:02.000]  For the king of the nation,
[00:02.000 --> 00:04.000]  for the king of the nation.
[00:04.000 --> 00:06.000]  Go be on the wheel!
[00:34.000 --> 00:40.120]  Not interested. I'm sorry. I'm sorry for the eventy, but I just can't do it. You're an e-girl. You know the world
[00:40.240 --> 00:48.080]  No e-girls who's got to clip don't eat girls never hashtag never e-girls not even once
[00:48.080 --> 00:55.080]  Yeah, I don't have to ever heard of it, but what is this that?
[01:48.080 --> 02:03.080]  Yeah, I've never heard of bigfoots, who's that?

但在Qt中通过以下代码捕获输出时,始终无法获取上述的转录内容:

connect( &p_Whisper, &QProcess::readyReadStandardError,[this, &p_Whisper](){
    ct_Error( p_Whisper.readAllStandardError() );
});
connect( &p_Whisper, &QProcess::readyReadStandardOutput,[this, &p_Whisper](){
    QString s = p_Whisper.readAllStandardOutput();
    ct_Process(s);
    ui->textBrowser->append(s);
});

用户尝试过channelReadyRead信号,但未触发:

connect( &p_Whisper, &QProcess::channelReadyRead,[this, &p_Whisper](int channel){
    p_Whisper.setCurrentReadChannel(channel);
    QString s = p_Whisper.readAllStandardOutput();
    ct_Process(s);
    ui->textBrowser->append(s);
});

也尝试过设置通道模式为ForwardedChannels,此时输出会转发到运行程序的Shell,但仍无法通过信号捕获。

补充信息:Whisper是Python封装的C子进程集合;Shell中将stdout/stderr重定向到文件时,stdout能成功捕获转录内容,说明Whisper不会因终端环境改变行为。

用户提出三个问题:

  1. 为何QProcess的readyRead信号无法捕获该stdout?
  2. 子进程的输出是否在QProcess的不同通道中?
  3. 是否可通过QProcess捕获目标stdout?是否有环境变量可辅助实现?

问题解答

1. 为何QProcess的readyRead信号无法捕获该stdout?

核心原因是Python的缓冲机制:当Python程序的stdout不是直接连接到终端(比如被QProcess管道捕获)时,会启用块缓冲模式,而非终端环境下的行缓冲。这意味着Whisper的转录输出会被暂时缓存,直到缓冲区填满或进程结束才会一次性输出,导致QProcess的readyReadStandardOutput信号无法实时触发,甚至可能在进程结束前都收不到数据。

另外,Whisper的Python层调用的C子进程,其输出同样可能因为非终端环境触发块缓冲,进一步延迟输出。

2. 子进程的输出是否在QProcess的不同通道中?

不是。根据Shell重定向测试结果,转录内容明确输出到stdout。QProcess启动的whisper进程作为父进程,其所有子进程的stdout默认会继承父进程的stdout通道,也就是QProcess监听的stdout管道。问题出在缓冲机制而非通道分配。

3. 是否可通过QProcess捕获目标stdout?是否有环境变量可辅助实现?

可以捕获,有两种可行方案:

  • 强制Python使用行缓冲:修改启动命令,让Python强制启用行缓冲。将/home/anon/.local/bin/whisper替换为python3 -u /home/anon/.local/bin/whisper(-u参数禁用缓冲,强制stdout/stderr使用行缓冲)。修改后的QProcess代码:
    p_Whisper.setProgram("python3");
    p_Whisper.setArguments( QStringList()
    << "-u"
    << "/home/anon/.local/bin/whisper"
    << "--model"                      << "medium.en"
    << "--output_dir"                 << d_Hidden.absolutePath()
    << "--task"                       << "transcribe"
    << "--language"                   << "en"
    << "--condition_on_previous_text" << "False"
    << "--no_speech_threshold"        << "0.5"
    << "--logprob_threshold"          << "None"
    << "--threads"                    << "8"
    << "--fp16"                       << "False"
    << "--verbose"                    << "True"
    << f.fileName()
    );
    
  • 设置环境变量:通过PYTHONUNBUFFERED环境变量强制Python无缓冲输出。在启动QProcess前添加:
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    env.insert("PYTHONUNBUFFERED", "1");
    p_Whisper.setProcessEnvironment(env);
    
    这个变量的作用和-u参数一致,无需修改启动程序路径,直接作用于Whisper的Python运行环境。

两种方案都能让Whisper的转录内容实时输出到stdout,触发QProcess的readyReadStandardOutput信号。


内容的提问来源于stack exchange,提问作者Jannies - They do it for free

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 01:20:37