我想以下列方式使用子进程模块:
stdout
(或stderr
,或两者一起或分别捕获)我已经使用Popen创建了进程,但是如果我使用communication(),那么一旦进程终止,数据就会立刻出现在我面前。
如果我创建了一个阻塞readline()
myprocess.stdout
的单独线程(使用stdout = subprocess.PIPE
),我也不会使用此方法获得任何行,直到进程终止。 (无论我设置为bufsize)
有没有办法处理这个并不可怕,并且在多个平台上运行良好?
答案 0 :(得分:8)
使用似乎无效的代码进行更新(无论如何在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
答案 1 :(得分:7)
stdout将被缓冲 - 因此在填充缓冲区或子进程退出之前,您将无法获得任何内容。
您可以尝试从子进程刷新stdout
,或使用stderr,或在非缓冲模式下更改stdout。
答案 2 :(得分:3)
这对我有用:
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()
,如python 0
(成功终止的返回码)也被视为False
。
答案 3 :(得分:2)
听起来问题可能是子进程使用缓冲输出 - 如果创建了相对少量的输出,则可以缓冲它直到子进程退出。可以找到一些背景here:
答案 4 :(得分:1)
我也遇到过这个问题。出现此问题的原因是您也尝试读取stderr。如果没有错误,那么尝试从stderr读取将阻止。
在Windows上,没有简单的方法来轮询()文件描述符(只有Winsock套接字)。
因此,解决方案不是尝试从stderr读取。
答案 5 :(得分:1)
将pexpect [http://www.noah.org/wiki/Pexpect]与非阻塞读取线一起使用可以解决此问题。它源于管道被缓冲的事实,因此你的应用程序的输出被管道缓冲,因此在缓冲区填充或进程死亡之前你无法获得该输出。
答案 6 :(得分:1)
这似乎是一个众所周知的Python限制,请参阅 PEP 3145以及其他人。
答案 7 :(得分:1)
一次阅读一个字符: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()
答案 8 :(得分:1)
使用subprocess.Popen,我可以运行我的一个C#项目的.exe并将输出重定向到我的Python文件。我现在能够print()
将所有信息输出到C#控制台(使用Console.WriteLine()
)到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文件。
答案 9 :(得分:0)
我已经使用了pexpect模块,它似乎工作正常。 http://sourceforge.net/projects/pexpect/