Когда я начинаю сценарий Python из другого сценария Python с помощью модуля подпроцесса, процесс-зомби создается, когда подпроцесс "завершается". Я не могу уничтожить этот подпроцесс, если я не уничтожаю свой родительский процесс Python.
Существует ли способ уничтожить подпроцесс, не уничтожая родителя? Я знаю, что могу сделать это при помощи ожидания (), но я должен запустить свой скрипт с no_wait ().
Зомби-процесс - это не настоящий процесс; это просто оставшаяся запись в таблице процессов до тех пор, пока родительский процесс не запросит код возврата дочернего процесса. Фактический процесс завершен и не требует никаких других ресурсов, кроме указанной записи в таблице процессов.
Нам, вероятно, понадобится больше информации о выполняемых вами процессах, чтобы действительно больше помогать.
Однако в случае, если ваша программа Python знает , когда дочерние процессы завершились (например, достигнув конца данных дочернего стандартного вывода), вы можете безопасно вызвать process.wait ( )
:
import subprocess
process= subprocess.Popen( ('ls', '-l', '/tmp'), stdout=subprocess.PIPE)
for line in process.stdout:
pass
subprocess.call( ('ps', '-l') )
process.wait()
print "after wait"
subprocess.call( ('ps', '-l') )
Пример вывода:
$ python so2760652.py
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 501 21328 21326 0 80 0 - 1574 wait pts/2 00:00:00 bash
0 S 501 21516 21328 0 80 0 - 1434 wait pts/2 00:00:00 python
0 Z 501 21517 21516 0 80 0 - 0 exit pts/2 00:00:00 ls <defunct>
0 R 501 21518 21516 0 80 0 - 608 - pts/2 00:00:00 ps
after wait
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 501 21328 21326 0 80 0 - 1574 wait pts/2 00:00:00 bash
0 S 501 21516 21328 0 80 0 - 1467 wait pts/2 00:00:00 python
0 R 501 21519 21516 0 80 0 - 608 - pts/2 00:00:00 ps
В противном случае вы можете сохранить всех дочерних элементов в списке и время от времени .poll
для их кодов возврата. После каждой итерации не забывайте удалять из списка дочерние элементы с кодами возврата, отличными от None
(т.е. завершенные).
Я не совсем понимаю, что вы имеете в виду под no_wait()
. Вы имеете в виду, что нельзя блокировать ожидание завершения дочерних процессов? Если так, то я думаю, что это сделает то, что вы хотите:
os.wait3(os.WNOHANG)
Неиспользование Popen.communicate ()
или call ()
приведет к зомби-процессу.
Если вам не нужен вывод команды, вы можете использовать subprocess.call ()
:
>>> import subprocess
>>> subprocess.call(['grep', 'jdoe', '/etc/passwd'])
0
Если вывод важен, вы должны использовать Popen ()
и communication ()
, чтобы получить stdout и stderr.
>>> from subprocess import Popen, PIPE
>>> process = Popen(['ls', '-l', '/tmp'], stdout=PIPE, stderr=PIPE)
>>> stdout, stderr = process.communicate()
>>> stderr
''
>>> print stdout
total 0
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 bar
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 baz
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 foo
Я не уверен, что вы имеете в виду "мне нужно запустить мой скрипт с no_wait()", но я думаю, что этот пример делает то, что вам нужно. Процессы не будут зомбироваться очень долго. Родительский процесс будет wait()
на них только тогда, когда они фактически уже завершены, и поэтому они быстро раззомбируются.
#!/usr/bin/env python2.6
import subprocess
import sys
import time
children = []
#Step 1: Launch all the children asynchronously
for i in range(10):
#For testing, launch a subshell that will sleep various times
popen = subprocess.Popen(["/bin/sh", "-c", "sleep %s" % (i + 8)])
children.append(popen)
print "launched subprocess PID %s" % popen.pid
#reverse the list just to prove we wait on children in the order they finish,
#not necessarily the order they start
children.reverse()
#Step 2: loop until all children are terminated
while children:
#Step 3: poll all active children in order
children[:] = [child for child in children if child.poll() is None]
print "Still running: %s" % [popen.pid for popen in children]
time.sleep(1)
print "All children terminated"
Вывод в конце выглядит так:
Still running: [29776, 29774, 29772]
Still running: [29776, 29774]
Still running: [29776]
Still running: []
All children terminated