2012-10-18 29 views
28

Câu hỏi rất cụ thể (Tôi hy vọng): Sự khác biệt giữa ba mã sau là gì?Python subprocess Popen.communicate() tương đương với Popen.stdout.read()?

(Tôi hy vọng nó sẽ được duy nhất mà là người đầu tiên không chờ đợi cho quá trình con được hoàn thành, trong khi những người thứ hai và thứ ba làm. Nhưng tôi cần phải chắc chắn đây là sự khác biệt chỉ ...)

tôi cũng hoan nghênh những nhận xét khác/gợi ý (mặc dù tôi đã nhận thức rõ về shell=True nguy hiểm và hạn chế cross-platform)

Lưu ý rằng tôi đã đọc Python subprocess interaction, why does my process work with Popen.communicate, but not Popen.stdout.read()? và rằng tôi không muốn/cần phải tương tác với chương trình sau.

Cũng lưu ý rằng tôi đã đọc Alternatives to Python Popen.communicate() memory limitations? nhưng mà tôi không thực sự có được nó ...

Cuối cùng, lưu ý rằng Tôi biết rằng ở đâu đó có một nguy cơ bế tắc khi một bộ đệm được làm đầy với một đầu ra sử dụng một phương pháp, nhưng tôi đã bị mất trong khi tìm kiếm lời giải thích rõ ràng trên Internet ...

mã đầu tiên:

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 

mã thứ hai:

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 

đang Thứ ba:

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 

Cảm ơn.

Trả lời

37

Nếu bạn nhìn vào các nguồn cho subprocess.communicate(), nó cho thấy một ví dụ hoàn hảo về sự khác biệt:

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) 

Bạn có thể thấy rằng communicate không tận dụng các cuộc gọi đọc để stdoutstderr, và cũng kêu gọi wait() . Nó chỉ là vấn đề trật tự của các hoạt động. Trong trường hợp của bạn bởi vì bạn đang sử dụng PIPE cho cả stdout và stderr, nó đi vào _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) 

này sử dụng chủ đề để đọc từ nhiều dòng cùng một lúc. Sau đó, nó gọi wait() ở cuối.

Vì vậy, để tóm tắt:

  1. Ví dụ này đọc từ một dòng tại một thời điểm và không chờ cho nó để kết thúc quá trình.
  2. Ví dụ này đọc từ cả hai luồng cùng một lúc thông qua các chuỗi nội bộ và chờ cho đến khi hoàn tất quá trình.
  3. Ví dụ này chờ quá trình kết thúc và sau đó đọc một luồng tại một thời điểm. Và như bạn đã đề cập có khả năng bế tắc nếu có quá nhiều văn bản cho các dòng.

Ngoài ra, bạn không cần hai câu lệnh import trong ví dụ thứ 2 và thứ 3 của mình:

from subprocess import communicate 
from subprocess import wait 

Họ là cả hai phương pháp của đối tượng Popen.