私はいくつかの解決策を考えることができます。
#1:ソースにアクセスして、コードcommunicate
を取得し、コピーして貼り付け、各行が入ってくるときに印刷するコードを追加し、バッファリングすることができます。(たとえば、親がデッドロックしているために自分stdout
でブロックできる場合は、threading.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
スレッドでエラー処理が必要になる場合があります。そして、私はあなたがreadline
ここで安全に使用できるかどうか100%確信していません。しかし、これはうまくいくか、近いでしょう。
#2:または、ファイルオブジェクトを取得し、誰かがそこから移動するたびにstdout
/にティーするラッパークラスを作成できます。次に、automagicを使用する代わりに、パイプを手動で作成し、ラップされたパイプを渡します。これには、#1とまったく同じ問題があります(問題がないか、ブロックできる場合は、または何かを使用する必要があることを意味します)。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、ディスクストレージを意味するこの「ファイルオブジェクト」のアイデアが心配な場合は、ウィキペディアの「すべてはファイルです」を読んでください。
#3:最後に、PyPIの「非同期サブプロセス」モジュールの1つを取得するか、twisted
または他の非同期フレームワークに含めて、それを使用できます。(これにより、デッドロックの問題を回避できますが、保証はされません。パイプを適切に保守する必要があります。)