Python逐行从子进程捕获stdout

我已经阅读了很多与此相关的问题并且学到了很多,但我仍然无法解决我的问题。 我正在构建一个运行c ++可执行文件的wxPython应用程序,并实时显示该可执行文件中的stdout。 我试图让这项工作遇到几个奇怪的结果。 这是我目前的设置/问题:

//test.cc (compiled as test.out with gcc 4.5.2) #include  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()将阻塞,直到程序的stdout缓冲区刷新,如果数据流是间歇性的,则可能需要很长时间。 如果您可以编辑源,一个选项是手动调用fflush(stdout),或者您可以在程序开始时使用setvbuf禁用缓冲。 例如:

 #include  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; } 

还要研究使用unbuffer或stdbuf来修改现有程序的输出流。