2010-06-23 6 views
14

Tengo un demonio de Python enhebrado. Como cualquier buen daemon, quiere lanzar todos sus hilos de trabajo, y luego esperar hasta que se le diga que finalice. La señal normal para la terminación es SIGTERM, y en la mayoría de los idiomas me gustaría esperar para terminar en un evento o mutex, por lo que usar threading.Event tenía sentido para mí. El problema es que el objeto Event de Python y las señales de Unix no parecen funcionar bien juntas.¿Por qué usar threading. El resultado del evento en SIGTERM no está atrapado?

esto funciona como se espera, que terminará el SIGTERM:

import signal 
import time 

RUN = True 

def handle(a, b): 
    global RUN 
    print "handled" 
    RUN = False 

signal.signal(signal.SIGTERM, handle) 
while RUN: 
    time.sleep(0.250) 
print "Stopping" 

pero esto no resulta en SIGTERM ser entregado (es decir, aparte de dejar de fumar, "manejado" Nunca se imprime):

import signal 
import threading 

RUN_EVENT = threading.Event() 

def handle(a, b): 
    print "handled" 
    RUN_EVENT.set() 

signal.signal(signal.SIGTERM, handle) 
RUN_EVENT.wait() 
print "Stopping" 

Así que mi pregunta es:

  1. Am I misusing threading.Event de alguna manera?
  2. Si no lo estoy, ¿hay alguna otra alternativa que no sea el mecanismo de sondeo y suspensión del primer ejemplo?
  3. Además, si no lo estoy, ¿por qué el uso de threading.Event mata al controlador de señal?

Respuesta

13

De Python documentation on signals:

Aunque los gestores de señales de Python se denominan de forma asíncrona en lo que concierne al usuario Python, sólo pueden ocurrir entre las instrucciones “atómicas” del intérprete de Python. Esto significa que las señales que llegan durante largos cálculos implementados puramente en C (como las coincidencias de expresiones regulares en cuerpos grandes de texto) pueden retrasarse durante un período de tiempo arbitrario.

He probado varios threading y thread clases y ninguno de ellos funcionan de la manera que usted desea - esto es probablemente debido a la forma en Python maneja señales. Sin embargo, en signal, existe una función pause() que duerme hasta que el proceso recibe una señal. Su ejemplo modificado sería este:

import signal 

RUN = True 

def handle(a, b): 
    global RUN 
    print "handled" 
    RUN = False 

signal.signal(signal.SIGTERM, handle) 
while RUN: 
    signal.pause() 
print "Stopping" 

Lo revisé en Linux, funciona. No creo que ya se clasifique como sondear y dormir si su aplicación no usa muchas otras señales.

+0

Característica molesta de Python, pero la solución perfecta. Gracias. Confesaré que no se me ocurrió buscar restricciones adicionales en el uso de 'señal ', ya que sabía que el equivalente C funcionaría bien. –

+3

¿Significa esto que la única manera de manejar las señales es dedicar el hilo principal (principal) a las señales de captura (bloqueando en 'signal.pause()')? Lo que eso implica es que el hilo principal ya no puede hacer nada útil. En otras palabras, no puede tener un modelo maestro/trabajador (donde los 2 hilos se comunican entre sí) pero necesita un modelo maestro/trabajador + trabajador (donde los 2 trabajadores hablan entre sí y el maestro no hace nada). –

Cuestiones relacionadas