2012-10-18 54 views
28

非常具體的問題(我希望):以下三個代碼有什麼區別?Python子進程Popen.communicate()等價於Popen.stdout.read()?

(我希望它是隻有第一沒有等待子進程來完成,而第二個和第三個做,但我需要確保這是唯一差異 ... )

我也歡迎其他評論/建議(雖然我已深知shell=True危險和跨平臺的限制)

注意的,我已經閱讀Python subprocess interaction, why does my process work with Popen.communicate, but not Popen.stdout.read()?,而我不希望/需要互動與程序之後。

另外請注意,我已經讀過Alternatives to Python Popen.communicate() memory limitations?但我並沒有真正得到它...

最後請注意,我知道冥冥之中有當一個緩衝區填充了一個輸出僵局的風險使用一種方法,但同時尋找在互聯網上解釋清楚我迷路了......

首先代碼:

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 

感謝。

回答

37

如果你看看源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() 。這只是一個操作順序問題。在你的情況,因爲你正在使用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. 本示例等待該過程完成,然後一次讀取一個流。正如你所提到的,如果寫入的流太多,就有可能陷入僵局。

而且,你並不需要這兩個import語句在你的第二和第三例子:

from subprocess import communicate 
from subprocess import wait 

他們是Popen對象的兩種方法。