Python: использование popen-опроса в фоновом процессе

В фоновом режиме я запускаю длинный процесс (фактически другой скрипт python). Мне нужно знать, когда он закончится. Я обнаружил, что Popen.poll() всегда возвращает 0 для фонового процесса. Есть ли другой способ сделать это?

p = subprocess.Popen("sleep 30 &", shell=True,
    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
a = p.poll()
print(a)

Выше кода никогда не печатает None.

Ответ 1

Вам не нужно использовать фоновые символы & синтаксис оболочки, так как subprocess запускает процесс в фоновом режиме

Просто запустите команду нормально, затем подождите, пока Popen.poll not None вернется.

import time
import subprocess

p = subprocess.Popen("sleep 30", shell=True)
# Better: p = subprocess.Popen(["sleep", "30"])

# Wait until process terminates
while p.poll() is None:
    time.sleep(0.5)

# It done
print "Process ended, ret code:", p.returncode

Ответ 2

Вы не должны запускать свой скрипт с амперсандом в конце. Поскольку оболочка разворачивает ваш процесс и возвращает код выхода 0.

Ответ 3

Я думаю, вам нужны команды popen.wait() или popen.communicate(). Общение будет захватывать данные stdout и stderr которые вы ввели в PIPE. Если другой элемент является скриптом Python, я бы избежал запуска shell=True вызова, выполнив что-то вроде:

p = subprocess.Popen([python.call, "my", params, (go, here)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = p.communicate()
print(stdout)
print(stderr)

Конечно, они держат основной поток и ждут завершения другого процесса, что может быть плохо. Если вы хотите заняться ожиданиями, вы можете просто обернуть исходный код в цикле. (Ваш исходный код напечатал "Нет" для меня, кстати)

Пример обертывания в решении цикла:

p = subprocess.Popen([python.call, "my", params, (go, here)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while p.poll() == None:
    # We can do other things here while we wait
    time.sleep(.5)
    p.poll()
(results, errors) = p.communicate()
if errors == '':
    return results
else:
    raise My_Exception(errors)