我可以想到一些解决方案。
#1:你可以直接进入源代码来获取的代码communicate,复制并粘贴它,添加代码来打印每一行,并缓冲内容。 (如果对你自己来说可能的话stdout
例如,由于父级陷入僵局而阻塞,您可以使用threading.Queue
或其他东西。)这显然有点 hacky,但它非常简单,而且很安全。
但实际上,communicate
很复杂,因为它需要完全通用,并处理您不具备的情况。这里你所需要的只是核心技巧:抛出线程来解决问题。专用的读取器线程,不会执行任何缓慢或阻塞的操作read
通话就是您所需要的。
像这样的事情:
self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE)
lines = []
def reader():
for line in self.process.stdout:
lines.append(line)
sys.stdout.write(line)
t = threading.Thread(target=reader)
t.start()
self.process.wait()
t.join()
您可能需要一些错误处理reader
线。我不能 100% 确定您可以安全地使用readline
这里。但这要么有效,要么接近。
#2:或者您可以创建一个包装类,它接受一个文件对象和 teesstdout
/stderr
每次有人read
是从它。然后手动创建管道,并传入包裹的管道,而不是使用 automagicPIPE
。这与#1 具有完全相同的问题(意味着要么没有问题,要么您需要使用Queue
或者如果sys.stdout.write
可以阻止)。
像这样的事情:
class TeeReader(object):
def __init__(self, input_file, tee_file):
self.input_file = input_file
self.tee_file = tee_file
def read(self, size=-1):
ret = self.input_file.read(size)
if ret:
self.tee_file.write(ret)
return ret
换句话说,它包装了一个文件对象(或类似文件对象的东西),并像文件对象一样工作。 (当你使用PIPE
, process.stdout
是 Unix 上的真实文件对象,但可能只是在 Windows 上起作用。)您需要委托给的任何其他方法input_file
可以直接委托,无需任何额外的包装。要么尝试这个,看看有什么方法communicate
gets AttributeException
明确地寻找并编码这些内容,或者执行通常的操作__getattr__
委派一切的技巧。 PS,如果您担心这个“文件对象”的想法意味着磁盘存储,请阅读一切都是文件在维基百科。
#3:最后,您可以获取 PyPI 上的“异步子进程”模块之一或包含在twisted
或其他异步框架并使用它。 (这使得possible以避免死锁问题,但事实并非如此保证—您仍然必须确保正确维修管道。)