Демон Python не уничтожает его детей

При использовании демона Python я создаю подпроцессы likeso:

import multiprocessing

class Worker(multiprocessing.Process):
   def __init__(self, queue):
      self.queue = queue # we wait for things from this in Worker.run()

   ...

q = multiprocessing.Queue()

with daemon.DaemonContext():
    for i in xrange(3):
       Worker(q)

    while True: # let the Workers do their thing
       q.put(_something_we_wait_for())

Когда я уничтожаю родителя daemonic процесс (т.е. не Рабочий) с Ctrl-C или SIGTERM, и т.д., дети не умирают. Как каждый уничтожает детей?

Моя первая мысль состоит в том, чтобы использовать atexit для уничтожения всех рабочих, likeso:

 with daemon.DaemonContext():
    workers = list()
    for i in xrange(3):
       workers.append(Worker(q))

    @atexit.register
    def kill_the_children():
        for w in workers:
            w.terminate()

    while True: # let the Workers do their thing
       q.put(_something_we_wait_for())

Однако дочерние элементы демонов являются хитрыми вещами обработать, и я был бы обязан для мыслей и входа о том, как это должно быть сделано.

Спасибо.

20
задан Brian M. Hunt 30 March 2010 в 02:59
поделиться

3 ответа

Ваши варианты: немного ограничено. Если выполнение self.daemon = True в конструкторе для класса Worker не решает вашу проблему и пытается перехватить сигналы в родительском (например, SIGTERM, SIGINT ]) не работает, возможно, вам придется попробовать противоположное решение - вместо того, чтобы заставить родителей убивать детей, вы можете заставить детей покончить жизнь самоубийством, когда родитель умрет.

Первый шаг - дать конструктору Worker PID родительского процесса (это можно сделать с помощью os.getpid () ). Затем вместо того, чтобы просто выполнять self.queue.get () в рабочем цикле, сделайте что-то вроде этого:

waiting = True
while waiting:
    # see if Parent is at home
    if os.getppid() != self.parentPID:
        # woe is me! My Parent has died!
        sys.exit() # or whatever you want to do to quit the Worker process
    try:
        # I picked the timeout randomly; use what works
        data = self.queue.get(block=False, timeout=0.1)
        waiting = False
    except queue.Queue.Empty:
        continue # try again
# now do stuff with data

Приведенное выше решение проверяет, отличается ли родительский PID от того, что был изначально ( то есть, если дочерний процесс был принят init или lauchd , потому что родитель умер) - см. ссылку . Однако, если это не сработает по какой-либо причине, вы можете заменить ее следующей функцией (адаптированной из здесь ):

def parentIsAlive(self):
    try:
        # try to call Parent
        os.kill(self.parentPID, 0)
    except OSError:
        # *beeep* oh no! The phone's disconnected!
        return False
    else:
        # *ring* Hi mom!
        return True

Теперь, когда Родитель умирает (по любой причине), дочерние Рабочие будут самопроизвольно падают, как мухи - как ты и хотел, демон! : - D

31
ответ дан 30 November 2019 в 00:09
поделиться

Atexit не поможет - он запускается только при успешном завершении без сигнала - см. Примечание в верхней части документации . Вам необходимо настроить обработку сигналов одним из двух способов.

Более простой вариант: установите флаг демона в ваших рабочих процессах, согласно http://docs.python.org/library/multiprocessing.html#process-and-exceptions

Немного сложнее option: PEP-3143 , похоже, подразумевает, что есть встроенный способ перехватить потребности очистки программы в python-daemon.

2
ответ дан 30 November 2019 в 00:09
поделиться

нельзя ли просто хранить pid родителя при первом создании ребенка (скажем, в self.myppid), а когда self.myppid отличается от getppid(), это означает, что родитель умер.

Вы также можете использовать сигналы, чтобы избежать необходимости постоянно проверять, изменился ли родитель. Я не знаю специфики python, но что-то вроде того, что описано здесь (внизу страницы), может сработать.

3
ответ дан 30 November 2019 в 00:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: