Согласно этой ветке, Марко Раухамаа пишет:
Если вам все равно, когда завершатся дочерние процессы, вы можете просто проигнорировать сигнал SIGCHLD:
import signal
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
Это предотвратит появление зомби.
На wait(2)
справочной странице поясняется:
В POSIX.1-2001 указано, что если для SIGCHLD задано значение SIG_IGN или установлен флаг SA_NOCLDWAIT для SIGCHLD (см. ) будет блокироваться до тех пор, пока не будут завершены все дочерние процессы, а затем завершится сбоем, когда для errno будет установлено значение ECHILD. (Исходный стандарт POSIX оставил поведение при установке SIGCHLD в SIG_IGN неопределенным. Обратите внимание, что хотя по умолчанию для SIGCHLD установлено значение «игнорировать», явная установка для SIG_IGN приводит к другому обращению с дочерними процессами-зомби.)
Linux 2.6 соответствует требованиям POSIX. Однако в Linux 2.4 (и более ранних версиях) этого не происходит: если вызов wait() или waitpid() выполняется, когда SIGCHLD игнорируется, вызов ведет себя так же, как если бы SIGCHLD не был проигнорирован, то есть вызов блокируется до следующего дочерний процесс завершается, а затем возвращает идентификатор процесса и статус этого дочернего процесса.
Поэтому, если вы используете Linux 2.6 или POSIX-совместимую ОС, использование приведенного выше кода позволит завершить дочерние процессы, не становясь зомби. Если вы не используете POSIX-совместимую ОС, то вышеприведенная ветка предлагает несколько вариантов. Ниже приведена одна альтернатива, несколько похожая на третье предложение Марко Раухамаа а>.
Если по какой-то причине вам нужно знать, когда дочерние процессы завершаются, и вы хотите обрабатывать (по крайней мере, некоторые из них) по-другому, вы можете настроить очередь, чтобы дочерние процессы могли сигнализировать основному процессу, когда они завершены. Затем основной процесс может вызвать соответствующее соединение в том порядке, в котором он получает элементы из очереди:
import time
import multiprocessing as mp
def exe(i, q):
try:
print(i)
if i == 1:
time.sleep(10)
elif i == 10:
raise Exception('I quit')
else:
time.sleep(3)
finally:
q.put(mp.current_process().name)
if __name__ == '__main__':
procs = dict()
q = mp.Queue()
for i in range(1,20):
proc = mp.Process(target=exe, args=(i, q))
proc.start()
procs[proc.name] = proc
while procs:
name = q.get()
proc = procs[name]
print(proc)
proc.join()
del procs[name]
print("finished")
дает результат, подобный
...
<Process(Process-10, stopped[1])> # <-- process with exception still gets joined
19
<Process(Process-2, started)>
<Process(Process-4, stopped)>
<Process(Process-6, started)>
<Process(Process-5, stopped)>
<Process(Process-3, stopped)>
<Process(Process-9, started)>
<Process(Process-7, stopped)>
<Process(Process-8, started)>
<Process(Process-13, started)>
<Process(Process-12, stopped)>
<Process(Process-11, stopped)>
<Process(Process-16, started)>
<Process(Process-15, stopped)>
<Process(Process-17, stopped)>
<Process(Process-14, stopped)>
<Process(Process-18, started)>
<Process(Process-19, stopped)>
<Process(Process-1, started)> # <-- Process-1 ends last
finished
person
unutbu
schedule
13.11.2018