2009-07-26 15 views
7

Considerare:Python: è os.read()/os.write() su un file os.pipe() threadsafe?

pipe_read, pipe_write = os.pipe() 

Ora, vorrei sapere due cose:

(1) Ho due fili. Se garantisco che solo uno sta leggendo os.read(pipe_read,n) e l'altro sta scrivendo solo os.write(pipe_write), avrò qualche problema, anche se i due thread lo fanno simultaneamente? Riceverò tutti i dati che sono stati scritti nell'ordine corretto? Cosa succede se lo fanno simultaneamente? E 'possibile che una singola scrittura viene letta in pezzi, come ?:

Thread 1: os.write(pipe_write, '1234567') 
Thread 2: os.read(pipe_read,big_number) --> '123' 
Thread 2: os.read(pipe_read,big_number) --> '4567' 

O - ancora una volta, considerare simultaneità - sarà un unico os.write(some_string) tornare sempre del tutto da un unico os.read(pipe_read, very_big_number)?

(2) consideri più di un thread per iscritto al pipe_write estremità del tubo utilizzando logging.handlers.FileHandler() - Ho letto che il modulo di registrazione è threadsafe. Questo significa che posso farlo senza perdere dati? Penso che non sarò in grado di controllare l'ordine dei dati nella pipe; ma questo non è un requisito. Requisiti:

  • tutti i dati scritti da alcuni fili alla fine scrittura devono venire fuori alla fine leggere
  • una stringa scritta da un singolo logger.info(), logger.error(), ... deve rimanere in un unico pezzo.

Queste richieste sono soddisfatte?

Grazie in anticipo,

Jan-Philip Gehrcke

+0

Btw: Sono a conoscenza di 'Queue.Queue()' e 'select.select()'. Nel mio caso particolare, la comunicazione da Thread A a Thread B sarà tramite 'Queue.Queue()': trasporta "comandi". Al contrario, B-> A trasporterà i messaggi di log e dovrebbe essere realizzato tramite 'os.pipe()' come descritto sopra, perché il thread A ha già implementato un ciclo di eventi basato su 'select.selezionare() ', che può monitorare' pipe_read' e richiamare una funzione di callback se c'è qualcosa di leggibile. –

risposta

8

os.read e os.write sui due FDS tornati dalla os.pipe è threadsafe, ma sembrano pretendere di più. Sub (1), sì, non esiste una garanzia di "atomicità" per le letture o le scritture di sinoli - lo scenario che si mostra (una singola scrittura breve finisce per produrre due letture) è interamente possibile. (In generale, os.whatever è un sottile involucro sulle funzionalità del sistema operativo e spetta al sistema operativo garantire o non garantire il tipo di funzionalità richiesto, in questo caso lo standard Posix non richiede il sistema operativo per garantire questo tipo di "atomicità"). Hai la garanzia di ottenere tutti i dati che sono stati scritti e nell'ordine corretto, ma il gioco è fatto. Una sola scrittura di una grande quantità di dati potrebbe bloccarsi una volta riempita la memoria del sistema operativo e solo una volta che qualche altro thread ha letto alcuni dati iniziali (attenzione ai deadlock, ovviamente!), Ecc. Ecc.

Sub (2), sì, il modulo di registrazione è thread-safe E "atomico" in quei dati prodotti da una singola chiamata a logging.info, logging.warn, logging.error, ecc., "Rimane tutto intero" in termini di chiamate al sottostante gestore (tuttavia se quel gestore a sua volta utilizza mezzi non atomici come os.write, potrebbe ancora ad esempio bloccarsi nel kernel fino a quando il buffer sottostante non viene chiuso, ecc. ecc., come sopra).

+1

Grazie mille per questa risposta. "Hai la garanzia di ottenere tutti i dati che sono stati scritti e nell'ordine corretto, ma questo è tutto" -> Questo è tutto ciò di cui ho bisogno, perché ciò significa che posso riassemblare i dati tritati con un piccolo post -os.read () routine. Ora posso iniziare a programmare con la coscienza pulita. Grazie, ancora :-) –

+0

Prego! All'inizio di ogni "scrittura" è possibile utilizzare un marcatore distinguibile per semplificare la post-elaborazione del rimontaggio. –

+0

Qualche aggiornamento: in realtà, devo usare 'StreamHandler() 'per la registrazione invece di' FileHandler() '. Da documenti Python: "StreamHandler()" "invia l'output di registrazione a [...] qualsiasi oggetto simile a file (o, più precisamente, qualsiasi oggetto che supporti i metodi' write() 'e' flush() '). , Devo racchiudere 'pipe_write' con' os.fdopen() ', per ottenere i metodi write e flush: ' logging.StreamHandler (os.fdopen (pipe_write, 'a', 0)) ' Spero di aver scelto delle buone opzioni senza alcuna modalità di buffering e append. –

Problemi correlati