¿El controlador atexit registrado es heredado por procesos hijos generados?
-
20-08-2019 - |
Pregunta
Estoy escribiendo un programa demonio usando Python 2.5. En el proceso principal, se registra un controlador de salida con el módulo atexit
, parece que se llama al controlador cuando finaliza cada proceso secundario, lo cual no es lo que esperaba.
Noté que este comportamiento no se menciona en python <=> doc, ¿alguien sabe el problema? Si así es como debería comportarse, ¿cómo puedo cancelar el registro del controlador de salida en los procesos secundarios? Hay un atexit.unregister en la versión 3.0, pero estoy usando 2.5.
Solución
No hay una API para hacerlo en Python 2.5, pero puedes simplemente:
import atexit
atexit._exithandlers = []
en sus procesos secundarios: si sabe que solo tiene un controlador de salida instalado y que no hay otros controladores instalados. Sin embargo, tenga en cuenta que algunas partes de stdlib (p. Ej., logging
) registran atexit
controladores. Para evitar pisotearlos, puedes intentar:
my_handler_entries = [e for e in atexit._exithandlers if e[0] == my_handler_func]
for e in my_handler_entries:
atexit._exithandlers.remove(e)
donde my_handler_func
es el <=> controlador que registró, y esto debería eliminar su entrada sin eliminar las demás.
Otros consejos
Cuando fork
realiza un proceso secundario, ese elemento secundario es una copia exacta del elemento primario, incluidas, por supuesto, las funciones de salida registradas, así como todas las demás estructuras de código y datos. Creo que ese es el problema que está observando, por supuesto, no se menciona en todos y cada uno de los módulos, porque necesariamente se aplica a cada uno.
atexit.register()
básicamente registra su función en atexit._exithandlers
, que es una lista privada de funciones del módulo llamada por sys.exitfunc()
. Puede configurar exitfunc()
a su función de controlador de salida personalizada, que luego verifica el estado secundario o simplemente lo anula. ¿Qué hay de copiar el 3.0 atexit.py
a su árbol de origen local y usarlo en su lugar?
EDITAR: copié el atexit.py de mi versión 2.6 y lo extendí
def unregister(func, *targs, **kargs):
_exithandlers.remove((func, targs, kargs))
Si toma eso en lugar de su versión original, debería funcionar. Sin embargo, no lo he probado con subprocesos.