Ответ 1
check_call()
возвращает, как только процесс /bin/sh
завершает работу, не дожидаясь процессов-потомков.
check_output()
ожидает, пока не будет прочитан весь вывод. Если ssh
наследует канал, то check_output()
будет ждать, пока он не выйдет (пока он не завершит свои унаследованные концы труб).
check_call()
пример кода:
#!/usr/bin/env python
import subprocess
import sys
import time
start = time.time()
cmd = sys.executable + " -c 'import time; time.sleep(2)' &"
subprocess.check_call(cmd, shell=True)
assert (time.time() - start) < 1
Выход не читается; check_call()
возвращает немедленно, не дожидаясь процесса фононов python внука.
check_call()
- это просто Popen().wait()
. Popen()
запускает внешний процесс и возвращается немедленно, не дожидаясь его выхода. .wait()
собирает статус выхода для процесса - он не ждет других (внуков) процессов.
Если вывод читается (он перенаправляется и python внука процесс наследует трубу stdout):
start = time.time()
subprocess.check_output(cmd, shell=True)
assert (time.time() - start) > 2
то он ждет, пока фоновый процесс python, унаследовавший выход канала.
check_output()
вызывает Popen().communicate()
, чтобы получить вывод. .communicate()
вызывает .wait()
внутренне, т.е. check_output()
также ожидает выхода оболочки, а check_output()
ожидает EOF.
Если внук не наследует канал, то check_output()
не ждет его:
start = time.time()
cmd = sys.executable + " -c 'import time; time.sleep(2)' >/dev/null &"
subprocess.check_output(cmd, shell=True)
assert (time.time() - start) < 1
Выход Grandchild перенаправляется на /dev/null
, т.е. он не наследует родительский канал, и поэтому check_output()
может выйти, не дожидаясь его.
Примечание: &
в конце, который переводит процесс python внука в фоновый режим. Он не будет работать в Windows, где shell=True
запускает cmd.exe
по умолчанию.