subprocess.Popen.stdout - 实时读取标准输出(再次)

时间:2010-06-29 11:28:56

标签: python subprocess stdout popen

同样,同样的问题。
原因是 - 阅读以下内容后仍然无法使其发挥作用:

我的情况是我有一个用C编写的控制台应用程序,让我们在循环中获取这个代码:

tmp = 0.0;   
printf("\ninput>>"); 
scanf_s("%f",&tmp); 
printf ("\ninput was: %f",tmp); 

它不断读取一些输入并写入一些输出。

我与之交互的python代码如下:

p=subprocess.Popen([path],stdout=subprocess.PIPE,stdin=subprocess.PIPE)
p.stdin.write('12345\n')
for line in p.stdout: 
    print(">>> " + str(line.rstrip())) 
    p.stdout.flush() 

到目前为止,每当我读取表单p.stdout时,它总是等待,直到进程终止然后输出一个空字符串。我尝试了很多东西 - 但结果仍然相同。

我尝试过Python 2.6和3.1,但版本并不重要 - 我只需要让它在某个地方工作。

5 个答案:

答案 0 :(得分:3)

尝试向管道写入和读取子流程是很棘手的,因为两个方向上的默认缓冲都在进行。在一个或另一个进程(父进程或子进程)从空缓冲区读取,写入完整缓冲区或在系统库刷新之前等待数据的缓冲区上执行阻塞读取时,非常容易出现死锁。

对于更适量的数据,Popen.communicate()方法可能就足够了。但是,对于超过缓冲的数据,您可能会遇到停滞过程(类似于您已经看到的过程?)

您可能希望查找有关使用fcntl模块以及使文件描述符中的一个或另一个(或两者)无阻塞的详细信息。在这种情况下,当然,您必须在适当的异常处理中包装对这些文件描述符的所有读取和/或写入,以处理“EWOULDBLOCK”事件。 (我不记得为这些引发的确切的Python异常。)

一种完全不同的方法是让您的父母在直接处理任何文件后使用select模块和os.fork() ...以及子进程到execve()目标程序()ING。 (基本上你将重新实现Popen()的部分,但使用不同的父文件描述符(PIPE)处理。

顺便说一下,.communicate,至少在Python的2.5和2.6标准库中,只能处理大约64K的远程数据(在Linux和FreeBSD上)。这个数字可能因各种因素而有所不同(可能包括用于编译Python解释器的构建选项,或者链接到它的libc版本)。它不仅仅受到可用内存的限制(尽管J.F.Sebastian断言相反),但仅限于更小的值。

答案 1 :(得分:1)

将管道中的读数推送到一个单独的线程中,该线程表示何时有一块输出可用:

How can I read all availably data from subprocess.Popen.stdout (non blocking)?

答案 2 :(得分:1)

bufsize=256参数阻止12345\n在小于256字节的块中发送到子进程,就像在省略bufsize或插入p.stdin.flush()之后一样p.stdin.write()。默认行为是行缓冲。

在任何一种情况下,你应该至少在阻塞之前看到一个空行,如你的例子中第一个printf(\n...)所发出的那样。

答案 3 :(得分:0)

您的特定示例不需要“实时”交互。以下作品:

from subprocess import Popen, PIPE

p = Popen(["./a.out"], stdin=PIPE, stdout=PIPE)
output = p.communicate(b"12345")[0] # send input/read all output
print output,

其中a.out是您的示例C程序。

通常,对于与子进程的基于对话框的交互,您可以使用pexpect模块(或Windows上的模拟):

import pexpect

child = pexpect.spawn("./a.out")
child.expect("input>>")
child.sendline("12345.67890") # send a number
child.expect(r"\d+\.\d+") # expect the number at the end
print float(child.after) # assert that we can parse it
child.close()

答案 4 :(得分:-1)

我遇到了同样的问题," proc.communicate()"没有解决它,因为它等待进程终止。

所以这里有什么对我有用,在 Windows Python 3.5.1

import subprocess as sp
myProcess = sp.Popen( cmd, creationflags=sp.CREATE_NEW_PROCESS_GROUP,stdout=sp.PIPE,stderr=sp.STDOUT)
while i<40:
        i+=1
        time.sleep(.5)
        out = myProcess.stdout.readline().decode("utf-8").rstrip()

我认为creationflags和其他参数不是强制性的(但我​​没有时间去测试),所以这将是最小的语法:

myProcess = sp.Popen( cmd, stdout=sp.PIPE)
for i in range(40)
            time.sleep(.5)
            out = myProcess.stdout.readline()