Python Как предотвратить многопроцессорные зомби при завершении работы ядра

недавно у меня возникла проблема с зомби-процессами при использовании многопроцессорности в Python.

У меня есть скрипт, который создает несколько процессов (рабочих), а также другой процесс (принтер). Рабочие будут создавать сообщения в очереди, а принтер должен распечатать все сообщения в очереди.

Проблема в том, что обычно рабочие должны работать часами. Но иногда после запуска скрипта хочется изменить код и перезапустить скрипт. Если я подожду, пока задание завершится, зомби не будет, так как я использую join(). Но если я отключу ядро ​​напрямую (поскольку ctrl+C не работает для моего спайдера), все процессы (зомби) все равно будут работать.

Я пытался использовать os.ppid, но кажется, что ppid не меняется. Я пробовал p.daemon = True, но тоже не работает.

Поэтому я хотел бы спросить, есть ли способ убедиться, что, если я выключу ядро, все процессы завершатся сами, и в системе не будет зомби.

Спасибо, пример кода:

from multiprocessing import Process, Queue
import time

def f(num, q):
    for i in range(100):
        q.put('f: num=%d\n'% (num,))
        time.sleep(10)
def g(q, filename):
    while True:
        with open(filename, 'a') as f:
            if q.qsize() > 0:
                item = q.get()
                if item == None:
                    break
                else:
                    f.write(item)
def main():
    filename = './log.txt'
    q = Queue()
    workers = [Process(target=f, args=(i,q)) for i in range(10)]
    printer = Process(target=g, args=(q,filename))
    for p in workers:
        p.daemon = True
        p.start()
    printer.daemon = True
    printer.start()
    for p in workers:
        p.join()
    q.put(None)
    printer.join()
if __name__ == '__main__':
    main()

person Yunguan    schedule 18.05.2017    source источник
comment
Что вы подразумеваете под выключением ядра? Какую команду вы на самом деле выдаете?   -  person noxdafox    schedule 18.05.2017
comment
На самом деле, я использую Spyder IDE и нажимаю квадратную кнопку, чтобы остановить текущую команду для консоли Ipython, или треугольную кнопку, которая убивает текущий процесс для консоли Python. Или я закрываю Spyder напрямую. Процессы-зомби есть всегда. Я тоже использовал Atom, и если я запущу скрипт и закрою Atom позже, будет такая же ситуация.   -  person Yunguan    schedule 18.05.2017
comment
Какую ОС вы используете?   -  person noxdafox    schedule 18.05.2017
comment
Ах... Windows :( Но я буду использовать Linux для запуска файла позже   -  person Yunguan    schedule 18.05.2017
comment
@Yunguan Просто к вашему сведению, это не «закрытие ядра». Если вы действительно должны закрыть ядро, ваш весь компьютер был бы фактически мертв.   -  person Akshat Mahajan    schedule 18.05.2017
comment
@AkshatMahajan Ах ... Я бы хотел сказать, консоль Python. Спасибо :)   -  person Yunguan    schedule 19.05.2017
comment
@AkshatMahajan Я не считаю, что ядро ​​​​неверно, поскольку оно используется в вопросе. Spyder использует iPython/Jupyter с различными ядрами (github.com/jupyter/jupyter/wiki /Jupyter-kernels) в качестве серверных частей.   -  person trianta2    schedule 25.09.2017


Ответы (1)


Дочерние процессы не освобождаются, потому что родительский процесс завершается внезапно без возможности очистки. Поэтому флаг daemon бесполезен.

Я бы не стал завершать процессы с дочерними элементами с помощью IDE, поскольку она, вероятно, не рассматривает такие варианты использования. Я бы предпочел полагаться на возможности ОС.

В Windows вы можете использовать команду Taskkill вместе с параметром /T. См. документацию по Taskkill.

В Linux вы можете использовать команду pkill с параметром -P. справочная страница Pkill.

В качестве последнего средства можно было бы перехватить сигнал SIGTERM и перенаправить его как SIGINT. Но я бы не рекомендовал это.

import os
from signal import signal, SIGINT, SIGTERM

def handler(*_):
    os.kill(os.pid, SIGINT)

signal.signal(SIGTERM, handler)

Это хак, и я даже не уверен, что он будет работать в Windows.

person noxdafox    schedule 18.05.2017
comment
Большое спасибо. Получается, что единственный способ — очистить этих зомби вручную? Я попробовал Taskkill, и он работает очень хорошо :) На данный момент я не очень хорошо понимаю код SIGTERM, но я поищу позже. Спасибо еще раз ! - person Yunguan; 19.05.2017
comment
Если ответ был полезен, отметьте его как правильный, чтобы другие люди могли легко его найти. Если ваша среда IDE допускает настройку (Atom позволяет), вы можете добавить ярлык. Если вы не совсем понимаете альтернативу SIGTERM, держитесь от нее подальше :). В любом случае это взлом. - person noxdafox; 19.05.2017
comment
ХОРОШО ! Большое вам спасибо!! :) Извините за опоздание. - person Yunguan; 20.05.2017