[英]How do I get 'real-time' information back from a subprocess.Popen in python (2.5)
我想以下列方式使用子进程模块:
stdout
(或stderr
,或可能两者,一起或分开) 我已经用Popen创建了进程,但是如果我使用communication(),那么一旦进程终止,数据就会立刻出现在我面前。
如果我创建一个单独的线程来执行myprocess.stdout
的阻塞readline()
(使用stdout = subprocess.PIPE
myprocess.stdout
),我也不会使用此方法获得任何行,直到进程终止。 (无论我设置为bufsize)
有没有办法解决这个不可怕的问题,并且在多个平台上运行良好?
更新代码似乎无法正常工作(无论如何在Windows上)
class ThreadWorker(threading.Thread):
def __init__(self, callable, *args, **kwargs):
super(ThreadWorker, self).__init__()
self.callable = callable
self.args = args
self.kwargs = kwargs
self.setDaemon(True)
def run(self):
try:
self.callable(*self.args, **self.kwargs)
except wx.PyDeadObjectError:
pass
except Exception, e:
print e
if __name__ == "__main__":
import os
from subprocess import Popen, PIPE
def worker(pipe):
while True:
line = pipe.readline()
if line == '': break
else: print line
proc = Popen("python subprocess_test.py", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout_worker = ThreadWorker(worker, proc.stdout)
stderr_worker = ThreadWorker(worker, proc.stderr)
stdout_worker.start()
stderr_worker.start()
while True: pass
stdout将被缓冲 - 因此在填充缓冲区或子进程退出之前,您将无法获得任何内容。
您可以尝试从子进程刷新stdout
,或使用stderr,或在非缓冲模式下更改stdout。
这对我有用:
cmd = ["./tester_script.bash"]
p = subprocess.Popen( cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
while p.poll() is None:
out = p.stdout.readline()
do_something_with( out, err )
在您的情况下,您可以尝试将对子流程的引用传递给您的工作线程,并在线程内部进行轮询。 我不知道当两个线程轮询(并与之交互)同一个子进程时它会如何表现,但它可能会起作用。
另请注意, while p.poll() is None:
按原样使用。 有没有取代它while not p.poll()
在蟒蛇0
(该返回码成功终止),也被认为是False
。
听起来问题可能是子进程使用缓冲输出 - 如果创建了相对少量的输出,则可以缓冲它直到子进程退出。 一些背景可以在这里找到:
这似乎是一个众所周知的Python限制,请参阅PEP 3145和其他人。
我也遇到过这个问题。 出现此问题的原因是您也尝试读取stderr。 如果没有错误,那么尝试从stderr读取将阻止。
在Windows上,没有简单的方法来轮询()文件描述符(只有Winsock套接字)。
因此,解决方案不是尝试从stderr读取。
一次阅读一个字符: http : //blog.thelinuxkid.com/2013/06/get-python-subprocess-output-without.html
import contextlib
import subprocess
# Unix, Windows and old Macintosh end-of-line
newlines = ['\n', '\r\n', '\r']
def unbuffered(proc, stream='stdout'):
stream = getattr(proc, stream)
with contextlib.closing(stream):
while True:
out = []
last = stream.read(1)
# Don't loop forever
if last == '' and proc.poll() is not None:
break
while last not in newlines:
# Don't loop forever
if last == '' and proc.poll() is not None:
break
out.append(last)
last = stream.read(1)
out = ''.join(out)
yield out
def example():
cmd = ['ls', '-l', '/']
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
# Make all end-of-lines '\n'
universal_newlines=True,
)
for line in unbuffered(proc):
print line
example()
使用带有非阻塞读取线的pexpect [ http://www.noah.org/wiki/Pexpect]将解决此问题。 它源于管道缓冲的事实,因此您的应用程序的输出被管道缓冲,因此在缓冲区填充或进程终止之前,您无法获得该输出。
使用subprocess.Popen,我可以运行我的一个C#项目的.exe并将输出重定向到我的Python文件。 我现在能够将所有输出到C#控制台的信息(使用Console.WriteLine()
) print()
到Python控制台。
Python代码:
from subprocess import Popen, PIPE, STDOUT
p = Popen('ConsoleDataImporter.exe', stdout = PIPE, stderr = STDOUT, shell = True)
while True:
line = p.stdout.readline()
print(line)
if not line:
break
这将在我的.NET项目创建时逐行获取控制台输出,并在项目终止时突破封闭的while循环。 我想这也适用于两个python文件。
我已经使用了pexpect模块,它似乎工作正常。 http://sourceforge.net/projects/pexpect/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.