python - ver - ¿Cómo matar procesos zombies creados por multiprocesamiento del módulo?
validar procesos zombie (3)
Un par de cosas:
Asegúrate de que el padre se
joins
sus hijos, para evitar zombies. Ver procesos de eliminación de multiprocesamiento de PythonPuede verificar si un niño todavía se está ejecutando con la función miembro
is_alive()
. Consulte http://docs.python.org/2/library/multiprocessing.html#multiprocessing.Process
Soy muy nuevo en el módulo multiprocessing
. Y solo traté de crear lo siguiente: Tengo un proceso que es un trabajo para obtener un mensaje de RabbitMQ y pasarlo a la cola interna ( multiprocessing.Queue
). Entonces, lo que quiero hacer es: generar un proceso cuando llega un nuevo mensaje. Funciona, pero una vez que finaliza el trabajo, deja un proceso zombie que no es terminado por su padre. Aquí está mi código:
Proceso principal:
#!/usr/bin/env python
import multiprocessing
import logging
import consumer
import producer
import worker
import time
import base
conf = base.get_settings()
logger = base.logger(identity=''launcher'')
request_order_q = multiprocessing.Queue()
result_order_q = multiprocessing.Queue()
request_status_q = multiprocessing.Queue()
result_status_q = multiprocessing.Queue()
CONSUMER_KEYS = [{''queue'':''product.order'',
''routing_key'':''product.order'',
''internal_q'':request_order_q}]
# {''queue'':''product.status'',
# ''routing_key'':''product.status'',
# ''internal_q'':request_status_q}]
def main():
# Launch consumers
for key in CONSUMER_KEYS:
cons = consumer.RabbitConsumer(rabbit_q=key[''queue''],
routing_key=key[''routing_key''],
internal_q=key[''internal_q''])
cons.start()
# Check reques_order_q if not empty spaw a process and process message
while True:
time.sleep(0.5)
if not request_order_q.empty():
handler = worker.Worker(request_order_q.get())
logger.info(''Launching Worker'')
handler.start()
if __name__ == "__main__":
main()
Y aquí está mi Trabajador:
import multiprocessing
import sys
import time
import base
conf = base.get_settings()
logger = base.logger(identity=''worker'')
class Worker(multiprocessing.Process):
def __init__(self, msg):
super(Worker, self).__init__()
self.msg = msg
self.daemon = True
def run(self):
logger.info(''%s'' % self.msg)
time.sleep(10)
sys.exit(1)
Entonces, después de que todos los mensajes se procesan, puedo ver los procesos con el comando ps aux
. Pero realmente me gustaría que terminen una vez que terminen. Gracias.
Usar multiprocessing.active_children
es mejor que Process.join
. La función active_children
limpia todos los zombies creados desde la última llamada a active_children
. El método de join
espera el proceso seleccionado. Durante ese tiempo, otros procesos pueden terminar y convertirse en zombies, pero el proceso principal no se notará, hasta que se junte el método esperado. Para ver esto en acción:
import multiprocessing as mp
import time
def main():
n = 3
c = list()
for i in xrange(n):
d = dict(i=i)
p = mp.Process(target=count, kwargs=d)
p.start()
c.append(p)
for p in reversed(c):
p.join()
print(''joined'')
def count(i):
print(''{i} going to sleep''.format(i=i))
time.sleep(i * 10)
print(''{i} woke up''.format(i=i))
if __name__ == ''__main__'':
main()
Lo anterior creará 3 procesos que terminan en 10 segundos cada uno. Como es el código, el último proceso se une primero, por lo que los otros dos, que terminaron antes, serán zombies durante 20 segundos. Puedes verlos con:
ps aux | grep Z
No habrá zombies si los procesos se esperan en la secuencia que terminarán. Retire el reversed
para ver este caso. Sin embargo, en aplicaciones reales rara vez conocemos la secuencia que los niños terminarán, por lo que el uso de la join
dará como resultado algunos zombies.
La alternativa active_children
no deja ningún zombies. En el ejemplo anterior, reemplace el bucle for p in reversed(c):
con:
while True:
time.sleep(1)
if not mp.active_children():
break
y mira lo que pasa.
Utilice active_children. multiprocessing.active_children