Supponiamo di aver configurato i gestori di registrazione nel processo principale. Il processo principale genera alcuni bambini ea causa di os.fork()
(in Linux) tutti i logger e i gestori vengono ereditati dal processo principale. Nell'esempio che segue 'Hello World'
verrebbero stampati 100 volte alla console:Come impedire l'ereditarietà di logger e gestori Python durante la multiprocessing basata su fork?
import multiprocessing as mp
import logging
def do_log(no):
# root logger logs Hello World to stderr (StreamHandler)
# BUT I DON'T WANT THAT!
logging.getLogger().info('Hello world {}'.format(no))
def main():
format = '%(processName)-10s %(name)s %(levelname)-8s %(message)s'
# This creates a StreamHandler
logging.basicConfig(format=format, level=logging.INFO)
n_cores = 4
pool = mp.Pool(n_cores)
# Log to stdout 100 times concurrently
pool.map(do_log, range(100))
pool.close()
pool.join()
if __name__ == '__main__':
main()
Questo stamperà qualcosa del tipo:
ForkPoolWorker-1 root INFO Hello world 0
ForkPoolWorker-3 root INFO Hello world 14
ForkPoolWorker-3 root INFO Hello world 15
ForkPoolWorker-3 root INFO Hello world 16
...
Tuttavia, non voglio il processo figlio di ereditare tutto la configurazione di registrazione dal genitore. Quindi nell'esempio sopra do_log
non dovrebbe stampare nulla su stderr
perché non ci dovrebbe essere StreamHandler
.
Come impedire di ereditare i registratori e i gestori senza rimuoverli o eliminarli nel processo padre originale?
EDIT: Sarebbe una buona idea per rimuovere semplicemente tutti i gestori durante l'inizializzazione della piscina?
def init_logging():
for logger in logging.Logger.manager.loggerDict.values():
if hasattr(logger, 'handlers'):
logger.handlers = []
e
pool = mp.Pool(n_cores, initializer=init_logging, initargs=())
Inoltre, posso anche tranquillamente close()
tutti (file) i gestori durante la funzione di inizializzazione?
'multiprocessing.Pool' ha una funzione di inizializzazione chiamata nel figlio ma non so come potrebbe disattivare tutti i gestori di registrazione senza un trucco sporco. – tdelaney
Potrei semplicemente dire 'logging.shutdown(); logging.Logger.manager.loggerDict = {} 'nell'inizializzatore? O questo interferirebbe con i nuovi gestori che creerò in seguito? O essere hacky? – SmCaterpillar
È stato definito per essere utilizzato all'uscita dall'applicazione, quindi non mi aspetto che sia una buona soluzione. Svuota anche tutti i buffer che sarebbero una brutta cosa (immagina un registratore di file). In effetti, sono sorpreso di non essermi imbattuto in questo problema da solo ... Non vedo l'ora di rispondere. Potrebbe essere una buona nuova funzionalità da aggiungere al logging. – tdelaney