Pergunta

Ao usar python-daemon, Estou criando subprocessos gostos:

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())

Quando mato o processo daemônico dos pais (ou seja, um trabalhador) com um Ctrl-C ou Sigterm, etc., as crianças não morrem. Como se mata as crianças?

Meu primeiro pensamento é usar ATEXIT Para matar todos os trabalhadores, gosta de:

 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())

No entanto, os filhos dos daemons são coisas complicadas de lidar, e eu seria obrigado por pensamentos e informações sobre como isso deveria ser feito.

Obrigada.

Foi útil?

Solução

Suas opções são um pouco limitadas. Se estiver fazendo self.daemon = True no construtor para o Worker A classe não resolve seu problema e tentando capturar sinais no pai (ou seja, SIGTERM, SIGINT) não funciona, você pode ter que tentar a solução oposta - em vez de fazer com que os pais matem os filhos, você pode fazer com que os filhos cometam suicídio quando os pais morrerem.

O primeiro passo é dar o construtor para Worker a PID do processo pai (você pode fazer isso com os.getpid()). Então, em vez de apenas fazer self.queue.get() No loop do trabalhador, faça algo assim:

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

A solução acima verifica para ver se o pai pai é diferente do que era originalmente (ou seja, se o processo infantil foi adotado por init ou lauchd Porque os pais morreram) - veja referência. No entanto, se isso não funcionar por algum motivo, você pode substituí -lo pela seguinte função (adaptada de aqui):

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

Agora, quando o pai morre (por qualquer motivo), as crianças cairão espontaneamente como moscas - exatamente como você queria, seu daemon! :-D

Outras dicas

Você não pode simplesmente armazenar o pid dos pais quando a criança é criada (digamos em self.myppid) e quando self.myppid é diferente de getppid() significa que os pais morreram.

Você também pode usar sinais para evitar a necessidade de verificar se o pai tiver alterado. Não conheço os detalhes do python, mas algo como o que é descrito Aqui (na parte inferior da página) pode funcionar.

Atexit não fará o truque-ele só é executado com terminação não-sinal bem-sucedida-veja a nota perto do topo do documentos. Você precisa configurar o manuseio de sinal através de um de dois meios.

A opção de som mais fácil: defina a bandeira daemon em seus processos de trabalhador, por http://docs.python.org/library/multiprocessing.html#process-and-eceptions

Opção um tanto mais difícil: PEP-3143 Parece sugerir que há uma maneira interna de conectar as necessidades de limpeza do programa em Python-Daemon.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top