За эту тему , Марко Раухамаа пишет:
Если вам не важно знать, когда завершаются дочерние процессы, вы можете просто проигнорировать сигнал SIGCHLD:
import signal
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
Это предотвратит появление зомби.
Справочная страница wait(2)
объясняет:
POSIX.1-2001 указывает, что если для расположения SIGCHLD установлено значение
SIG_IGN или флаг SA_NOCLDWAIT установлен для SIGCHLD (см.
sigaction (2)), то дети, которые заканчиваются, не становятся зомби и
вызов wait () или waitpid () будет блокироваться, пока все дети не
завершается, а затем завершается ошибкой с 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