Ответ 1
Если вы посмотрите на источник 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
использует вызовы чтения для stdout
и stderr
, а также вызывает wait()
. Это всего лишь вопрос порядка операций. В вашем случае, потому что вы используете PIPE
для stdout и stderr, он переходит в _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()
в конце.
Итак, чтобы подвести итог:
- Этот пример читается из одного потока за раз и не ждет завершения процесса.
- Этот пример читает оба потока одновременно с помощью внутренних потоков и ждет завершения процесса.
- Этот пример ждет завершения процесса, а затем читает один поток за раз. И, как вы упомянули, есть потенциал для тупиковой ситуации, если слишком много написано в потоках.
Кроме того, вам не нужны эти два оператора импорта во втором и третьем примерах:
from subprocess import communicate
from subprocess import wait
Это оба метода объекта Popen
.