我可以想到一些解决方案。
#1:您可以直接进入源代码以获取,复制和粘贴的代码communicate
,并添加可打印每行内容的代码以及对它们进行缓冲的代码。(如果您可能stdout
由于死锁的父母而被自己阻止,则可以改用athreading.Queue
或其他东西。)这显然有点麻烦,但这很简单,而且很安全。
但实际上,这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:或者您可以创建一个包装器类,该包装器类接受一个文件对象,并在每次有人访问它时发球到stdout
/ 。然后,手动创建管道,并传递包裹的管道,而不是使用automagic 。这个问题与#1完全相同(意味着没有问题,或者您需要使用a或其他内容(如果可以阻止))。stderr``read``PIPE``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
得到AttributeException
,正在寻找和代码的那些明确,或者做一般的__getattr__
伎俩委托的一切。PS,如果您担心这种“文件对象”的想法,即磁盘存储,请阅读Wikipedia上的Everything是一个文件。
#3:最后,您可以获取PyPI上的“异步子进程”模块之一,或将其包含在twisted
其他异步框架中或使用它。(这使得它 能够 避免死锁问题,但它不保证 -你还是要确保服务管道正常。)