Il gestore di atexit registrato è ereditato da processi figlio generati?
-
20-08-2019 - |
Domanda
Sto scrivendo un programma demone usando Python 2.5. Nel processo principale un gestore di uscita è registrato con il modulo atexit
, sembra che il gestore venga chiamato quando termina ogni processo figlio, cosa che non mi aspettavo.
Ho notato che questo comportamento non è menzionato in Python <=> doc, qualcuno conosce il problema? Se è così che dovrebbe comportarsi, come posso annullare la registrazione del gestore di uscita nei processi secondari? C'è un atexit.unregister nella versione 3.0, ma sto usando 2.5.
Soluzione
Non esiste un'API per farlo in Python 2.5, ma puoi semplicemente:
import atexit
atexit._exithandlers = []
nei processi secondari: se sai che è installato un solo gestore di uscita e che non sono installati altri gestori. Tuttavia, tenere presente che alcune parti dello stdlib (ad es. logging
) registrano atexit
gestori. Per evitare di calpestarli, potresti provare:
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)
dove my_handler_func
è il gestore <=> che hai registrato e questo dovrebbe rimuovere la tua voce senza rimuovere le altre.
Altri suggerimenti
Quando si fork
per eseguire un processo figlio, quel figlio è una copia esatta del genitore, incluse ovviamente le funzioni di uscita registrate, nonché tutte le altre strutture di codice e dati. Credo che questo sia il problema che stai osservando - ovviamente non è menzionato in ogni singolo modulo, perché si applica necessariamente a ciascuno di essi.
atexit.register()
registra sostanzialmente la tua funzione in atexit._exithandlers
, che è un elenco privato di funzioni del modulo chiamato da sys.exitfunc()
. È possibile impostare exitfunc()
sulla funzione del gestore di uscita personalizzata, che verifica quindi lo stato del figlio o semplicemente lo annulla. Che ne dici di copiare semplicemente il 3.0 atexit.py
nel tuo albero dei sorgenti locale e usarlo invece?
EDIT: ho copiato atexit.py dalla mia versione 2.6 e l'ho esteso di
def unregister(func, *targs, **kargs):
_exithandlers.remove((func, targs, kargs))
Se lo prendi invece della versione originale dovrebbe funzionare. Non l'ho testato con sottoprocessi, tuttavia.