2012-10-18 36 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对象的两种方法。