Блокировка и блокировка подпроцессов

Я полностью запутался между subprocess.call(), subprocess.Popen(), subprocess.check_call().

Что блокирует, а что нет?

Что я хочу сказать, если я использую subprocess.Popen(), ожидает ли родительский процесс дочернего процесса return/exit, прежде чем он продолжит выполнение.

Как shell=True влияет на эти вызовы?

Ответ 1

Popen неблокируется. call и check_call блокируются. Вы можете сделать блок экземпляра Popen, вызвав его метод wait или communicate.

Если вы посмотрите исходный код, вы увидите call calls Popen(...).wait(), поэтому он блокирует. check_call вызывает call, поэтому он также блокирует.

Строго говоря, shell=True ортогонален проблеме блокировки. Однако shell=True заставляет Python запускать оболочку, а затем запускать команду в оболочке. Если вы используете блокирующий вызов, вызов вернется, когда оболочка закончит. Так как оболочка может порождать подпроцесс для запуска команды, оболочка может завершиться до порожденного подпроцесса. Например,

import subprocess
import time

proc = subprocess.Popen('ls -lRa /', shell=True)
time.sleep(3)
proc.terminate()
proc.wait()

Здесь возникают два процесса: Popen порождает один подпроцесс, запускающий оболочку. В свою очередь оболочка запускает подпроцесс, выполняющийся ls. proc.terminate() убивает оболочку, но работает подпроцесс ls. (Это проявляется в обильном выходе, даже после завершения python script. Будьте готовы убить ls с помощью pkill ls.)