Popen
を使用してサブプロセスを起動し、生成時にほぼリアルタイムで出力を消費するPythonプログラムがあります。関連するループのコードは次のとおりです。
def run(self, output_consumer):
self.prepare_to_run()
popen_args = self.get_popen_args()
logging.debug("Calling popen with arguments %s" % popen_args)
self.popen = subprocess.Popen(**popen_args)
while True:
outdata = self.popen.stdout.readline()
if not outdata and self.popen.returncode is not None:
# Terminate when we've read all the output and the returncode is set
break
output_consumer.process_output(outdata)
self.popen.poll() # updates returncode so we can exit the loop
output_consumer.finish(self.popen.returncode)
self.post_run()
def get_popen_args(self):
return {
'args': self.command,
'shell': False, # Just being explicit for security's sake
'bufsize': 0, # More likely to see what's being printed as it happens
# Not guarantted since the process itself might buffer its output
# run `python -u` to unbuffer output of a python processes
'cwd': self.get_cwd(),
'env': self.get_environment(),
'stdout': subprocess.PIPE,
'stderr': subprocess.STDOUT,
'close_fds': True, # Doesn't seem to matter
}
これは本番マシンではうまく機能しますが、開発マシンでは、.readline()
特定のサブプロセスが完了すると呼び出しがハングします。つまり、「処理が完了しました」という最終出力行を含むすべての出力を正常に処理しますが、再度ポーリングreadline
して戻ることはありません。このメソッドは、私が呼び出すほとんどのサブプロセスの開発マシンで適切に終了しますが、それ自体が多くのサブプロセスを呼び出す1つの複雑なbashスクリプトでは常に終了できません。
出力が終了する何行も前に、 (通常は)値以外の値popen.returncode
に設定されることに注意してください。したがって、それが設定されているときにループから抜け出すことはできません。そうしないと、プロセスの最後に吐き出され、読み取りを待ってバッファリングされているすべてのものが失われます。問題は、その時点でバッファをフラッシュしているときに、最後の呼び出しがハングするため、いつ終了したかがわからないことです。呼び出しもハングします。電話をかけると、最後のすべてのキャラクターが出てきますが、最後の行の後でハングします。 常にです。私が最後にいることをどのように知ることができますか?None
0
readline()
read()
read(1)
popen.stdout.closed
False
すべてのシステムは、Ubuntu12.04LTSでpython2.7.3を実行しています。FWIWは、を使用しstderr
てマージされています。stdout
stderr=subprocess.STDOUT
なぜ違いがあるのですか?stdout
なんらかの理由で閉まりませんか?サブサブプロセスは、それを何らかの形で開いたままにするために何かを行うことができますか?開発ボックスのターミナルからプロセスを起動しているのに、本番環境ではデーモンとして起動されているためsupervisord
でしょうか?それはパイプの処理方法を変更しますか?もしそうなら、どのようにそれらを正規化しますか?