基本的に、重複する 2 つの制御スレッドがあります。
- 入力をサブプロセスに送信します。
- サブプロセスからデータが利用可能になったときに読み取ります。
プラットフォームに依存しない方法でこれを行うと、スレッド (または選択ループ) を使用する以外に多くのオプションが得られません。
問題のコードは標準出力にのみ関心があるように見えるため、標準出力を読み取って内容をファイルに書き込むスレッドを呼び出すだけで済みます。
次に例を示します。
import subprocess
import os
import threading
class LogThread(threading.Thread):
"""Thread which will read from `pipefd` and write all contents to
`fileobj` until `pipefd` is closed. Used as a context manager, this thread
will be automatically started, and joined on exit, usually when the
child process exits.
"""
def __init__(self, pipefd, fileobj):
self.pipefd = pipefd
self.fileobj = fileobj
super(LogThread, self).__init__()
self.setDaemon(1)
self.start()
def run(self):
while True:
line = self.pipefd.readline()
if not line:
break
self.fileobj.write(line)
self.fileobj.flush()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.join()
# Here's how to use the LogThread.
p = subprocess.Popen ("script", shell = False, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
with open('logfile.txt', 'wt') as logfile:
with LogThread(p.stdout, logfile):
p.stdin.write("\n".join(in_lines))
p.stdin.close()
これはおそらく の小さな部分を複製Popen.communicate()
しますが、多くのコードではなく、プラットフォームに依存しません。
バッファリングに関する注意:
stdout が非 tty デバイス (パイプなど) にバッファリングされるのは正常です。通常、stderr はバッファリングされません。通常、実行中のアプリケーションがその出力をバッファリングするかどうかを制御することはできません。せいぜい、バッファリングを使用するかどうかを決定する方法を推測することができます。ほとんどのアプリケーションは、バッファリングするisatty()
必要があるかどうかを決定するために呼び出します。そのため、ログ ファイルにバッファリング 0 を設定することは、バッファリングを回避するための正しい解決策ではない可能性があります。バッファリングが 0 の場合、出力の各文字は単一のwrite()
呼び出しとして書き込まれ、非常に非効率的です。上記のソリューションは、行バッファリングを実行するように変更されました。
次のリンクが役に立つかもしれません: https://unix.stackexchange.com/questions/25372/turn-off-buffering-in-pipe