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.

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top