29

非常に具体的な質問 (希望):次の 3 つのコードの違いは何ですか?

(最初のプロセスは子プロセスが終了するのを待たず、2 番目と 3 番目のプロセスは終了するだけだと思います。しかし、これが唯一の違いであることを確認する必要があります...)

他の意見や提案も歓迎します (ただし、shell=True危険性とクロスプラットフォームの制限については十分に認識しています) 。

Python サブプロセス インタラクションを既に読んでいることに注意してください。なぜ私のプロセスは Popen.communicate で動作するのに、Popen.stdout.read() で動作しないのですか? そして、後でプログラムとやり取りしたくない/する必要がないこと。

また、既にPython Popen.communicate() メモリ制限の代替案を読んでいることにも注意してください。しかし、私は本当にそれを理解していませんでした...

最後に、1つの方法を使用して1つのバッファが1つの出力で満たされると、どこかでデッドロックのリスクがあることを認識していますが、インターネットで明確な説明を探している間に迷子になりました...

最初のコード:

from subprocess import Popen, PIPE

def exe_f(command='ls -l', shell=True):
    """Function to execute a command and return stuff"""

    process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

    stdout = process.stdout.read()
    stderr = process.stderr.read()

    return process, stderr, stdout

2 番目のコード:

from subprocess import Popen, PIPE
from subprocess import communicate

def exe_f(command='ls -l', shell=True):
    """Function to execute a command and return stuff"""

    process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

    (stdout, stderr) = process.communicate()

    return process, stderr, stdout

3 番目のコード:

from subprocess import Popen, PIPE
from subprocess import wait

def exe_f(command='ls -l', shell=True):
    """Function to execute a command and return stuff"""

    process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

    code   = process.wait()
    stdout = process.stdout.read()
    stderr = process.stderr.read()

    return process, stderr, stdout

ありがとう。

4

1 に答える 1

38

のソースを見るとsubprocess.communicate()、違いの完全な例が示されています。

def communicate(self, input=None):
    ...
    # Optimization: If we are only using one pipe, or no pipe at
    # all, using select() or threads is unnecessary.
    if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
        stdout = None
        stderr = None
        if self.stdin:
            if input:
                self.stdin.write(input)
            self.stdin.close()
        elif self.stdout:
            stdout = self.stdout.read()
            self.stdout.close()
        elif self.stderr:
            stderr = self.stderr.read()
            self.stderr.close()
        self.wait()
        return (stdout, stderr)

    return self._communicate(input)

communicateと への読み取り呼び出し、stdoutおよび呼び出しstderrも利用していることがわかりますwait()。それは単に操作の順序の問題です。あなたの場合PIPE、stdout と stderr の両方に使用しているため、次のようになります_communicate()

def _communicate(self, input):
    stdout = None # Return
    stderr = None # Return

    if self.stdout:
        stdout = []
        stdout_thread = threading.Thread(target=self._readerthread,
                                         args=(self.stdout, stdout))
        stdout_thread.setDaemon(True)
        stdout_thread.start()
    if self.stderr:
        stderr = []
        stderr_thread = threading.Thread(target=self._readerthread,
                                         args=(self.stderr, stderr))
        stderr_thread.setDaemon(True)
        stderr_thread.start()

    if self.stdin:
        if input is not None:
            self.stdin.write(input)
        self.stdin.close()

    if self.stdout:
        stdout_thread.join()
    if self.stderr:
        stderr_thread.join()

    # All data exchanged.  Translate lists into strings.
    if stdout is not None:
        stdout = stdout[0]
    if stderr is not None:
        stderr = stderr[0]

    # Translate newlines, if requested.  We cannot let the file
    # object do the translation: It is based on stdio, which is
    # impossible to combine with select (unless forcing no
    # buffering).
    if self.universal_newlines and hasattr(file, 'newlines'):
        if stdout:
            stdout = self._translate_newlines(stdout)
        if stderr:
            stderr = self._translate_newlines(stderr)

    self.wait()
    return (stdout, stderr)

これは、スレッドを使用して複数のストリームから一度に読み取ります。そして、最後に呼び出しますwait()

要約すると:

  1. この例では、一度に 1 つのストリームから読み取り、プロセスが完了するまで待機しません。
  2. この例では、内部スレッドを介して両方のストリームから同時に読み取り、プロセスが完了するまで待機します。
  3. この例では、プロセスが終了するのを待ってから、一度に 1 つのストリームを読み取ります。また、ストリームへの書き込みが多すぎると、デッドロックが発生する可能性があります。

また、2 番目と 3 番目の例では、次の 2 つの import ステートメントは必要ありません。

from subprocess import communicate
from subprocess import wait

どちらもPopenオブジェクトのメソッドです。

于 2012-10-18T23:27:56.003 に答える