簡體   English   中英

Python子進程Popen.communicate()相當於Popen.stdout.read()?

[英]Python subprocess Popen.communicate() equivalent to Popen.stdout.read()?

非常具體的問題(我希望): 以下三個代碼之間有什么區別?

(我希望它只是第一個不等待子進程完成,而第二個和第三個進行。但我需要確定這是唯一的區別......)

我也歡迎其他評論/建議(雖然我已經很清楚shell=True危險和跨平台限制)

請注意,我已經閱讀過Python子進程交互,為什么我的進程可以使用Popen.communicate,但不能使用Popen.stdout.read()? 並且我不希望/之后需要與程序交互。

另請注意,我已經閱讀了Python Popen.communicate()內存限制的替代品? 但是我沒有真正得到它......

最后,請注意我知道當一個緩沖區使用一種方法填充一個輸出時存在死鎖的風險,但我在互聯網上尋找清晰的解釋時迷路了...

第一個代碼:

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

第二個代碼:

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

第三個代碼:

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

謝謝。

如果你查看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確實利用了對stdoutstderr的讀取調用,並且還調用了wait() 這只是一個操作順序問題。 在你的情況下,因為你對stdout和stderr使用PIPE ,它進入_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. 此示例一次從一個流中讀取,並且不等待它完成該過程。
  2. 此示例通過內部線程同時從兩個流中讀取,並等待它完成該過程。
  3. 此示例等待進程完成,然后一次讀取一個流。 正如你所提到的那樣,如果寫入流中的內容過多,則可能會出現死鎖。

此外,在第2和第3個示例中,您不需要這兩個import語句:

from subprocess import communicate
from subprocess import wait

它們都是Popen對象的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM