2012-10-18 17 views
28

Domanda molto specifica (spero): Quali sono le differenze tra i seguenti tre codici?Sottoprocesso Python Popen.communicate() equivalente a Popen.stdout.read()?

(mi aspetto che sia solo il primo non attendere che il processo figlio da rifinire, mentre il secondo e il terzo fanno. Ma ho bisogno di essere sicuri che questo è l'unico differenza ...)

Accolgo con favore anche altre osservazioni/suggerimenti (anche se sono già ben consapevoli dei pericoli e limitazioni shell=True cross-platform)

Nota che ho già letto Python subprocess interaction, why does my process work with Popen.communicate, but not Popen.stdout.read()? e che io non voglio/bisogno di interagire con il programma dopo.

Si noti inoltre che ho già letto Alternatives to Python Popen.communicate() memory limitations? ma che non ho davvero capito ...

Infine, ricordiamo che sono consapevole che da qualche parte c'è il rischio di deadlock quando un buffer viene riempito con un'uscita utilizzando un metodo, ma mi sono perso durante la ricerca di spiegazioni chiare su Internet ...

primo codice:

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 

secondo codice:

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 

terzo codice:

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 

Grazie.

risposta

37

Se si guarda alla fonte per subprocess.communicate(), mostra un perfetto esempio della differenza:

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) 

Si può vedere che communicate fa di utilizzo delle chiamate di lettura per stdout e stderr, e chiede anche wait() . È solo una questione di ordine delle operazioni. Nel tuo caso, perché si sta utilizzando PIPE sia per stdout e stderr, va in _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) 

Questo utilizza i thread di leggere da più flussi in una sola volta. Quindi chiama wait() alla fine.

Quindi, per riassumere:

  1. Questo esempio legge da un flusso alla volta e non aspetta che finisca il processo.
  2. Questo esempio legge entrambi i flussi allo stesso tempo tramite thread interni e attende che finisca il processo.
  3. Questo esempio attende il completamento del processo e quindi legge un flusso alla volta. E come hai detto ha il potenziale di deadlock se c'è troppo scritto nei flussi.

Inoltre, non hanno bisogno di queste due affermazioni di importazione nel vostro esempi 2 e 3:

from subprocess import communicate 
from subprocess import wait 

Sono entrambi metodi dell'oggetto Popen.

Problemi correlati