2011-12-06 16 views
5

Possiedo un programma possibilmente long che attualmente ha 4 processi, ma potrebbe essere configurato per avere di più. Ho ricercato logging from multiple processes usando python logging e sto usando l'approccio SocketHandler discusso here. Non ho mai avuto problemi con un unico logger (senza prese), ma da quello che ho letto mi è stato detto che sarebbe fallito alla fine e inaspettatamente. Per quanto ne so è sconosciuto cosa succederà quando proverai a scrivere sullo stesso file nello stesso momento. Il mio codice fa essenzialmente i seguenti:Registrazione di Python da più processi

import logging 
log = logging.getLogger(__name__) 

def monitor(...): 
    # Spawn child processes with os.fork() 
    # os.wait() and act accordingly 

def main(): 
    log_server_pid = os.fork() 
    if log_server_pid == 0: 
     # Create a LogRecordSocketServer (daemon) 
     ... 
     sys.exit(0) 
    # Add SocketHandler to root logger 
    ... 
    monitor(<configuration stuff>) 

if __name__ == "__main__": 
    main() 

Quindi le mie domande sono: Ho bisogno di creare un nuovo oggetto log dopo ogni os.fork()? Cosa succede all'attuale oggetto globale log?

Con il fare le cose come sono, riesco anche a risolvere il problema che sto cercando di evitare (più file aperti/socket)? Questo fallirà e perché fallirà (mi piacerebbe essere in grado di dire se future implementazioni simili falliranno)?

Inoltre, in che modo il metodo "normale" (un'espressione log=) di registrazione su un file da più processi non riesce? Alza un IOError/OSError? O semplicemente non scrive completamente i dati nel file?

Se qualcuno potesse fornire una risposta o dei collegamenti per aiutarmi, sarebbe grandioso. Grazie.

FYI: sto testando su Mac OS X Lion e il codice sarà probabilmente a finire in esecuzione su un CentOS 6 VM su una macchina Windows (se quello che conta). Qualunque sia la soluzione che uso non ha bisogno di lavorare su Windows, ma dovrebbe funzionare su un sistema basato su Unix.

UPDATE: Questa domanda ha iniziato ad allontanarsi dalla registrazione di comportamenti specifici ed è più nel regno di ciò che fa Linux con i descrittori di file durante i fork. Ho tirato fuori uno dei miei libri di testo del college e sembra che se apri un file in modalità append da due processi (non prima di un fork) che entrambi saranno in grado di scrivere correttamente nel file purché la tua scrittura non superi il vero buffer del kernel (sebbene potrebbe essere necessario utilizzare il buffering di riga, non è ancora sicuro su quello). Questo crea 2 voci di tabella file e una voce di tabella v-nodo. L'apertura di un file quindi non dovrebbe funzionare, ma sembra che non superi il buffer del kernel come prima (l'ho fatto in un programma precedente).

Quindi, suppongo che, se si desidera la registrazione multiprocessing indipendente dalla piattaforma, si utilizzano socket e si crea un nuovo SocketHandler dopo ogni fork per essere sicuri, come suggerito da Vinay di seguito (che dovrebbe funzionare ovunque). Per me, dal momento che ho un forte controllo su quale sistema operativo viene eseguito il mio software, penso che andrò con un oggetto globale log con un FileHandler (si apre in modalità di aggiunta per impostazione predefinita e con buffer di riga sulla maggior parte dei SO). La documentazione per open dice "Un buffer negativo significa utilizzare l'impostazione predefinita di sistema, che di solito è la linea bufferizzata per i dispositivi tty e completamente bufferizzata per altri file. Se omessa, viene utilizzata l'impostazione predefinita del sistema." oppure potrei semplicemente creare il mio flusso di registrazione per essere sicuro del buffer di linea. E tanto per essere chiari, io sto bene con:

# Process A 
a_file.write("A\n") 
a_file.write("A\n") 
# Process B 
a_file.write("B\n") 

produzione ...

A\n 
B\n 
A\n 

fintanto che non produce ...

AB\n 
\n 
A\n 

Vinay (o chiunque altro), quanto sia sbagliato sono io? Fammi sapere. Grazie per la maggiore chiarezza/sicurezza che puoi fornire.

+0

I thread e i blocchi sono utili per cose come questa ... –

+0

Ho bisogno di processi separati mentre i bambini stanno comunicando con dispositivi esterni che dovrebbero essere il più "veloci" possibile. – daveydave400

+0

Ho aggiornato la mia risposta. –

risposta

2

Devo creare un nuovo oggetto registro dopo ogni os.fork()? Cosa succede all'oggetto log globale esistente?

AFAIK l'oggetto log globale continua a puntare allo stesso registratore nei processi padre e figlio. Quindi non dovresti aver bisogno di crearne uno nuovo. Tuttavia, penso che dovresti creare e aggiungere SocketHandler dopo il fork() in monitor(), in modo che il server socket abbia quattro connessioni distinte, una per ogni processo figlio. Se non si esegue questa operazione, i processi secondari disattivati ​​in monitor() erediteranno SocketHandler e il relativo handle di socket dai relativi genitori, ma non so per certo che si comportino male. È probabile che il comportamento sia dipendente dal sistema operativo e potresti essere fortunato su OSX.

Con il fare le cose come sono, mi sto anche aggirando il problema che sto cercando di evitare (più file aperti/socket)? Questo fallirà e perché fallirà (mi piacerebbe essere in grado di dire se future implementazioni simili falliranno)?

non mi aspetto fallimento se si crea la connessione socket al server presa dopo l'ultimo fork() come ho suggerito sopra, ma io non sono sicuro che il comportamento è ben definito in tutti gli altri casi. Si fa riferimento a più file aperti ma non vedo alcun riferimento all'apertura di file nel proprio snippoclip pseudocodice, semplicemente aprendo i socket.

Inoltre, in che modo il metodo "normale" (un log = espressione) di registrazione su un file da più processi fallisce? Alza un IOError/OSError? O semplicemente non scrive completamente i dati nel file?

Penso che il comportamento non sia ben definito, ma ci si aspetterebbe che le modalità di errore si presentino come messaggi di registro intercalati da processi diversi nel file, ad es.

Process A writes first part of its message 
Process B writes its message 
Process A writes second part of its message 

Aggiornamento: Se si utilizza un FileHandler nel modo hai descritto nel tuo commento, le cose non saranno così buono, a causa dello scenario che ho descritto sopra: processo A e B entrambi iniziano indicando la fine del file (a causa della modalità append), ma da quel momento in poi le cose possono andare fuori sincrono perché (ad esempio su un multiprocessore, ma potenzialmente anche su un uniprocessore), un processo può (preemptene un altro e) scrivere sull'handle di file condiviso prima un altro processo ha finito di farlo.

+0

Quando ho detto più file intendevo se avessi fatto un FileHandler di base invece di uno SocketHandler. Ho parlato con un collega e ha detto che se la registrazione apre un FileHandler in modalità append su Linux, dovrei essere ok (un oggetto log, un gestore file, più fork). Pensieri? E creare SocketHandlers dopo una fork ha senso. – daveydave400

+0

Ho aggiornato la mia domanda, grazie. – daveydave400

+0

Accetterò la tua risposta a causa della creazione di SocketHandler dopo il fork, ma non sono ancora d'accordo con la modalità append (il kernel dovrebbe rendere append atomics). – daveydave400

Problemi correlati