Почему я получаю предупреждения о ресурсах подпроцесса, несмотря на то, что процесс мертв?

Я пытался понять, как запускать разные экземпляры подпроцессов, а затем убивать их, а затем создавать новые. Родительский процесс Python никогда этого не делает, он просто убивает подпроцессы. Я перешел по многим ссылкам на SO, но после завершения родительского процесса python я продолжаю получать следующее сообщение:

F/Users/Lucifer/miniconda3/envs/rltp/lib/python3.6/subprocess.py:761: ResourceWarning: subprocess 40909 is still running ResourceWarning, source=self)

это кажется интересным, потому что я сделал ps, но ничего не получил:

  PID TTY           TIME CMD
 7070 ttys001    0:00.06 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp Lucifer
 7072 ttys001    0:00.61 -bash
17723 ttys002    0:00.06 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp Lucifer
17725 ttys002    0:00.06 -bash
38586 ttys002    0:00.16 sertop --no_init

Я просто хочу запустить процесс:

self.serapi = subprocess.Popen(['sertop','--no_init'],
    stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,
    preexec_fn=os.setsid,shell=True
    ,)

и убить его:

    os.killpg(os.getpgid(self.serapi.pid), signal.SIGTERM)

приведенный выше код по существу скопирован из верхнего ответа:

Как завершить подпроцесс python, запущенный с помощью shell=True< /а>

но я не уверен, почему я получаю это сообщение. Я успешно убиваю дочерний процесс? Я планирую начать и убить многих из них.


Примечание. Я не знаю или не нуждаюсь в shell=True. Я просто скопировал это, потому что таков ответ / вопрос, который я разместил. Я бы предпочел не иметь этого параметра.


согласно ответу, который я пробовал:

def kill(self):
    self.serapi.wait()
    #self.serapi.kill()
    self.serapi.terminate()
    #os.killpg(os.getpgid(self.serapi.pid), signal.SIGTERM)
    #self.serapi.wait()

и различные перестановки вышеперечисленного, но на самом деле ничего не работало. Любой совет?


person Charlie Parker    schedule 07.03.2019    source источник
comment
Вы wait() участвовали в подпроцессе? Даже после выхода дочерний процесс остается зомби до тех пор, пока его родитель не вызовет wait() и не получит его статус выхода.   -  person Daniel Pryden    schedule 07.03.2019
comment
@DanielPryden Я не звонил wait() Я не знал, что этот звонок существует, пока вы не упомянули об этом.   -  person Charlie Parker    schedule 08.03.2019
comment
Большой! Я так и думал, поэтому и написал ответ ниже. Если вы нашли его полезным, пожалуйста, не стесняйтесь голосовать и/или принимать его. Рад, что смог помочь!   -  person Daniel Pryden    schedule 08.03.2019
comment
@DanielPryden, глядя на доки, вызывающие wait(), кажется, заходит в тупик, если оба являются stdout,stderr = PIPE, кроме того, мой процесс никогда не заканчивается, пока я не скажу ему закончить.   -  person Charlie Parker    schedule 08.03.2019


Ответы (1)


Предупреждение ResourceWarning: subprocess N is still running исходит из метода __del__ класса subprocess.Popen.

Если вы посмотрите на источник этого метода, вы увидите этот комментарий:

        # Not reading subprocess exit status creates a zombie process which
        # is only destroyed at the parent python process exit
        _warn("subprocess %s is still running" % self.pid,
              ResourceWarning, source=self)

Решение состоит в том, чтобы убедиться, что вы вызываете wait() для дочернего процесса.

См. раздел ПРИМЕЧАНИЯ на странице руководства для wait(2). для получения дополнительной справочной информации.

В Python самый простой способ справиться с этой ситуацией — отслеживать все созданные вами объекты Popen и убедиться, что что-то вызывает wait() прямо или косвенно.

В качестве альтернативы вы можете установить обработчик SIGCHLD, игнорирующий события SIGCHLD; тогда ваши дочерние процессы немедленно исчезнут, но вы теперь не сможете вызывать для них wait(). См. также Как предотвратить дочерние процессы зомби? и Как я могу обрабатывать SIGCHLD?

person Daniel Pryden    schedule 07.03.2019
comment
Я пробовал разные варианты следующего self.serapi.wait();#self.serapi.kill();#self.serapi.terminate();, но это не сработало. Итак, я предполагаю, что вызов wait(), а затем завершение / уничтожение процесса не работает? Или я что-то упускаю? - person Charlie Parker; 08.03.2019
comment
а процесс еще идет? Я не понимаю, что происходит, потому что когда я делаю ps, я этого не вижу... :/ - person Charlie Parker; 08.03.2019
comment
Вы должны сначала убить процесс, а затем подождать его. На уровне ядра wait буквально означает не ожидание, а получение посмертной информации. На самом деле процесс может и не быть зомби, в зависимости от того, как вы его разветвите. Но класс Popen думает, что подпроцесс все еще должен быть запущен (или должен быть зомби), потому что вы еще не получили никакой информации о вскрытии. Имеет ли это смысл? - person Daniel Pryden; 08.03.2019
comment
Хорошо, поэтому я называю wait (действительно плохое название для того, для чего оно должно быть) после kill. Как узнать, все ли прошло успешно? Я уверен, что пробовал это, но не было ясно, сработало ли это. Я пытаюсь запустить новый подпроцесс для каждого из моих модульных тестов. Я хотел бы создать новый подпроцесс. - person Charlie Parker; 11.03.2019