c++ - Python逐行从子进程捕获stdout

标签 c++ python c multithreading wxpython

我已经阅读了很多与此相关的问题并学到了很多东西,但我仍然无法解决我的问题。我正在构建一个运行 c++ 可执行文件并实时显示该可执行文件的标准输出的 wxPython 应用程序。为了使这项工作成功,我遇到了几个奇怪的结果。这是我当前的设置/问题:

//test.cc (compiled as test.out with gcc 4.5.2)
#include <stdio.h>
int main()
{
  FILE* fh = fopen("output.txt", "w");
  for (int i = 0; i < 10000; i++)
  {
      printf("Outputting: %d\n", i);
      fprintf(fh, "Outputting: %d\n", i);
  }
  fclose(fh);
  return 0;
}

#wxPythonScript.py (running on 2.7 interpreter)
def run(self):
  self.externalBinary = subprocess.Popen(['./test.out'], shell=False, stdout=subprocess.PIPE)
  while not self.wantAbort:
      line = self.externalBinary.stdout.readline()
      wx.PostEvent(self.notifyWindow, Result_Event(line, Result_Event.EVT_STDOUT_ID))
    print('Subprocess still running')
  print('Subprocess aborted smoothly')

如果我运行上面的代码,子进程需要很长时间才能完成,即使它所要做的只是写出数据并退出。但是,如果我运行以下命令,它会很快完成:

#wxPythonScript.py (running on 2.7 interpreter)
def run(self):
  outFile = open('output.txt', 'r+')
  self.externalBinary = subprocess.Popen(['./test.out'], shell=False, stdout=outFile)
  while not self.wantAbort:
      #line = self.externalBinary.stdout.readline()
      #wx.PostEvent(self.notifyWindow, Result_Event(line, Result_Event.EVT_STDOUT_ID))
    print('Subprocess still running')
  print('Subprocess aborted smoothly')

所以基本上每当我将 stdout 从子进程重定向到 PIPE 时,它都会减慢/挂起,但如果我将它写入文件或根本不重定向它,那就没问题了。这是为什么?

最佳答案

我只在 Windows 上测试过它,但它适用于 2.6.6、2.7.2 和 3.2.1:

from __future__ import print_function
from subprocess import PIPE, Popen
from threading  import Thread
import sys

try:
    from Queue import Queue, Empty
except ImportError:
    from queue import Queue, Empty  # python 3.x

ON_POSIX = 'posix' in sys.builtin_module_names

def enqueue_output(out, queue):
    for line in iter(out.readline, b''):
        line = line.decode(sys.stdout.encoding)
        queue.put(line)
    out.close()

def main():
    p = Popen(['c/main.exe'], stdout=PIPE, bufsize=1, close_fds=ON_POSIX)
    q = Queue()
    t = Thread(target=enqueue_output, args=(p.stdout, q))
    t.daemon = True # thread dies with the program
    t.start()

    #initially the queue is empty and stdout is open
    #stdout is closed when enqueue_output finishes
    #then continue printing until the queue is empty 

    while not p.stdout.closed or not q.empty():
        try:
            line = q.get_nowait()
        except Empty:
            continue
        else:
            print(line, end='')
    return 0

if __name__ == '__main__':
    sys.exit(main())

输出:

Outputting: 0
Outputting: 1
Outputting: 2
...
Outputting: 9997
Outputting: 9998
Outputting: 9999

编辑:

readline() 将阻塞直到程序的标准输出缓冲区刷新,如果数据流是间歇性的,这可能需要很长时间。如果您可以编辑源代码,一种选择是手动调用 fflush(stdout),或者您可以在程序开始时使用 setvbuf 禁用缓冲。例如:

#include <stdio.h>

int main() {

    setvbuf(stdout, NULL, _IONBF, 0);

    FILE* fh = fopen("output.txt", "w");
    int i;

    for (i = 0; i < 10; i++) {
        printf("Outputting: %d\n", i);
        fprintf(fh, "Outputting: %d\n", i);
        sleep(1);
    }

    fclose(fh);
    return 0;
}

同时考虑使用 unbufferstdbuf修改现有程序的输出流。

关于c++ - Python逐行从子进程捕获stdout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7608883/

相关文章:

c - 空白行段。错误(自己写shell)

c++ - C 解决方案,有人可以向我解释这段代码吗?

c++ - 理性类和 move 语义不起作用

python - 无法从终端运行 Flask, “No module named ' my_app'”

c - C中的向后递归打印

c - 即使两个字符串都正常,strcmp 也会崩溃

c++ - 使用 T 写入 uint8_t

c++ - OpenGL 着色器加载失败

python - Django 分析

python - Pycassa,线程池, "Exception in thread Thread-3 (most likely raised during interpreter shutdown):"