web-dev-qa-db-ja.com

なぜpython.subprocessがproc.communicate()の後にハングするのですか?

my_own_exeというインタラクティブなプログラムがあります。最初にaliveを出力し、次にS\nを入力してから、もう一度aliveを出力します。最後にL\nを入力します。いくつかの処理を実行して終了します。

ただし、次のpythonスクリプトから呼び出すと、最初の「生きている」を出力した後、プログラムがハングしたように見えました。

ここの誰かがなぜこれが起こっているのか教えてもらえますか?

//フォローアップを読んだ後(ありがとう)、コードを次のように変更しました:

import subprocess
import time

base_command = "./AO_FelixStrategy_UnitTest --bats 31441 --chix 12467 --enxutp 31884 --turq 26372 --symbol SOGN --target_date " + '2009-Oct-16'
print base_command

proc2 = subprocess.Popen(base_command, Shell=True , stdin=subprocess.PIPE,)

time.sleep(2);
print "aliv"
proc2.communicate('S\n')

print "alive"
time.sleep(6)

print "alive"
print proc2.communicate('L\n')
time.sleep(6)

プログラムは最初の入力「S\n」でうまくいきますが、その後停止し、2番目の「L\n」はちょっと無視されます。

なぜこんな感じなのか、誰か教えてもらえますか?

16
James Bond

communicateのドキュメント から:

プロセスとの対話:データをstdinに送信します。ファイルの終わりに達するまで、stdoutおよびstderrからデータを読み取ります。 プロセスが終了するのを待ちます。

したがって、communicate()が実行された後、プロセスは終了しました

プロセスが停止するのを待たずに書き込みと読み取りを行う場合:

  • ever_Shell=True_を使用しないでください-それは針状にシェルを呼び出してプログラムを呼び出すので、あなたとあなたのプログラムの間に別のプロセスがあります。それには多くの不快な副作用があります。デフォルトは_Shell=False_なので、これを維持する必要があります。 Popen行を次のように変更します。

    _p = subprocess.Popen(["./AO_FelixStrategy_UnitTest",
                          "--bats", "31441", "--chix", "12467",
                          "--enxutp", "31884", "--turq", "26372",
                          "--symbol", "SOGN", "--target_date", '2009-Oct-16'],
                         stdin=subprocess.PIPE, 
                         stdout=subprocess.PIPE)
    _
  • _p.stdin.write_を使用してプロセスに書き込みます。 _p.stdout.read_を使用して読み取ります。

  • 読み取るものがない場合に_p.stdout.read_を呼び出すと、ブロックされます。書き込みバッファがいっぱいの場合に_p.stdin.write_を呼び出すと、ブロックされます。したがって、読み取り/書き込みができるものがあることを確認する必要があります。これは、UNIXOSでselectを使用して行います。 Windowsでは、残念ながらスレッドに頼らなければなりません。少なくともそれは_Popen.communicate_が内部で行うことです。
  • _AO_FelixStrategy_UnitTest_を記述しなかった場合は、さらに問題が発生する可能性があります:
    • 標準入力ではなく、別の場所から読み取っている可能性があります。ターミナルから直接読み取るプログラムもあれば、OSAPIを使用して読み取るプログラムもあります。つまり、stdinに書き込まれたデータはプログラムに送られません。これは多くの場合、パスワードプロンプトに当てはまります。
    • _AO_FelixStrategy_UnitTest_バッファを考慮する必要があることに注意してください。デフォルトでは、標準のC PIPE通信はバッファリングされているため、入力側を閉じるまで出力が表示されない場合があります(p.stdin.close()を実行します。_AO_FelixStrategy_UnitTest_が出力を定期的にフラッシュしない限り。

説明内容に基づいたサンプルコードを次に示します。 _AO_FelixStrategy_UnitTest_がどのように開発されたかによっては機能する可能性があります。

_p = subprocess.Popen(["./AO_FelixStrategy_UnitTest",
                      "--bats", "31441", "--chix", "12467",
                      "--enxutp", "31884", "--turq", "26372",
                      "--symbol", "SOGN", "--target_date", '2009-Oct-16'],
                     stdin=subprocess.PIPE, 
                     stdout=subprocess.PIPE)
output = p.communicate('S\nL\n')[0]
print output
_
30
nosklo

communicate() stdoutおよびstderrからデータを読み取りますファイルの終わりに達するまで。 -プログラムが終了するまで待機します。

4
Messa

comunicateは1回だけ実行され、パイプを閉じるため、複数のコマンドを送信する場合これに、同じ文字列で次々に送信する必要があります。

これは、スレッド、subprocess32、stdin.write、stdout.readなどを試した後、私のために働いた例です。この情報は、公式のpython通信用の参照情報にはありません:- https://docs.python.org/2/library/subprocess.html

私がこれを見つけた唯一の場所はここでした: Pythonサブプロセス通信は私のプロセスを殺します

いずれにせよ、ここにコードがあります。シンプルで、スレッドもサブプロセスもありません32。LinuxとWindowsで動作します。はい、他のプロセスにコマンドを送信する回数を知っている必要がありますが、一般的にはそれを知っています。これに加えて、スレッド、cwd、Shell = True、またはその他の必要なものを追加できますが、これは最も単純なケースです。

def do_commands(self, cmd, parms):
    proc = subprocess.Popen(cmd,  stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE )

    # wait for the process to terminate
    out, err = process.communicate(cmd_parms)
    errcode = process.returncode

    return errcode, out, err

したがって、たとえば、呼び出されているアプリケーションに複数のキャリッジリターン(\ n)を送信し、途中のパラメータ(インタラクティブに気になります)を送信する場合は、次のように呼び出します。

cmd_parms = "\n\n\n\n\nparm\n\n"

errcode, out, err = do_commands(command, cmd_parms)
1
Tomas