Popen.communicate застревает, пока процесс, порожденный подпроцессом, не завершится - PullRequest
0 голосов
/ 19 октября 2018

У меня есть три нижеприведенных скрипта, и когда я запускаю файл main.py, он порождает child.py, который снова выполняет subchild.py и быстро завершает работу, однако subchild.py продолжает выполняться в течение длительного времени.

Проблема в том, что main.py блокируется в p.communicate () до тех пор, пока subchild.py не завершится.Если я открою диспетчер задач и уничтожу работающий файл subchild.py, main.py немедленно вернет вывод child.py

, поэтому мои вопросы будут такими, как показано ниже

  • main.py долженждать только до завершения child.py, почему он ожидает завершения subchild.py?
  • Как заставить p.communicate () не ждать, пока subchild.py завершит свое выполнение?
    # main.py file

    if __name__ == '__main__':
        import subprocess
        p = subprocess.Popen(
            ["python", "child.py"],
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        out, _ = p.communicate()
        print(out)


    # child.py file

    if __name__ == '__main__':
        import subprocess
        print("Child running")
        p = subprocess.Popen(["python", "subchild.py"])
        print("Child pid - ", p.pid)
        exit(1)


    # subchild.py file

    if __name__ == '__main__':
        import time
        time.sleep(10000)

Примечание: я пытаюсь это сделать в Windows 7 Enterprise.Я использую python3.6.6

Обновление после комментария: В main.py мне нужны объект pid, stdout, stderr и process для child.py, чтобы я мог убить child.py изmain.py в любой момент, если я захочу.Этот код представляет собой небольшой фрагмент кода, являющийся частью некоторого API, который я создаю, где пользователь хотел бы, чтобы элемент управления убил процесс, если он этого хочет.subprocesses.call или subprocesses.run не позволили бы мне получить контроль над объектом process.У меня также не будет контроля над тем, какую команду child.py я получу в качестве входных данных для main.py, поэтому мне нужно как-то не ждать subchild.py и немедленно завершить работу с выходом child.py, как только он завершится.

Ответы [ 3 ]

0 голосов
/ 19 октября 2018

Ваш communicate звонок не просто ждет, пока ребенок завершит.Сначала он пытается прочитать все содержимое дочерних stdout и stderr.

Даже после завершения дочернего процесса родитель не может прекратить чтение, поскольку внук наследует дочерние stdin, stdout иSTDERR .Родителю нужно подождать, пока внук завершится, или, по крайней мере, внук закроет свои stdout и stderr, прежде чем родитель сможет быть уверен, что он завершил чтение.

0 голосов
/ 19 октября 2018

Наконец-то я сам нашел решение, похоже, это открытая проблема с python.Был бы рад видеть это исправленным.https://bugs.python.org/issue26731

0 голосов
/ 19 октября 2018

Прямо сейчас child.py всегда будет ждать окончания subchild.py.Если вам не нужно ждать, вы можете попробовать subprocess.call() в качестве альтернативы в коде child.py.Замените логику Popen() на логику call().

p = subprocess.call(["python", "subchild.py"])

Вот ссылка: https://docs.python.org/2/library/subprocess.html#subprocess.call


Альтернативой является сохранение кода, поскольку он фактически является изменением использования .call() в файле main.py,

import subprocess
p = subprocess.call(
    ["python", "child.py"],
    stdout=subprocess.PIPE,
    stdin=subprocess.PIPE,
    stderr=subprocess.PIPE
)

Вы упомянули, что не можете использовать .call (), потому что вам нужно его убить, однако это не так.Внесение этого изменения должно позволить вам:

  • быстро возвращать main.py и child.py,
  • будет печатать идентификатор процесса дочернего процесса из child.py и
  • subchild.py продолжит работу
...