2009-09-11 6 views
12

Ho una domanda generale sul popen (e su tutte le funzioni correlate), applicabile a tutti i sistemi operativi, quando scrivo uno script python o un codice c ed eseguo l'eseguibile risultante da la console (win o linux), posso immediatamente vedere l'output del processo. Tuttavia, se eseguo lo stesso eseguibile di un processo forked con il suo stdout reindirizzato in una pipe, l'output buffer da qualche parte, in genere fino a 4096 byte prima che venga scritto nella pipe dove il processo padre può leggerlo.Bypassare il buffering dell'output di sottoprocesso con popen in C o Python

Il seguente script pitone genererà uscita in blocchi di 1024 byte

import os, sys, time 

if __name__ == "__main__": 
    dye = '@'*1024 
    for i in range (0,8): 
     print dye 
     time.sleep(1) 

Il seguente script python eseguirà lo script precedente e leggere l'output appena arriva al tubo, byte per byte

import os, sys, subprocess, time, thread 

if __name__ == "__main__": 
    execArgs = ["c:\\python25\\python.exe", "C:\\Scripts\\PythonScratch\\byte_stream.py"] 

    p = subprocess.Popen(execArgs, bufsize=0, stdout=subprocess.PIPE) 
    while p.returncode == None: 
     data = p.stdout.read(1) 
     sys.stdout.write(data) 
     p.poll() 

Regolare il percorso per il sistema operativo. Quando viene eseguito in questa configurazione, l'output non verrà visualizzato in blocchi di 1024 ma blocchi di 4096, nonostante la dimensione del buffer del comando popen sia impostata su 0 (che è comunque l'impostazione predefinita). Qualcuno può dirmi come modificare questo comportamento ?, c'è un modo in cui posso forzare il sistema operativo a trattare l'output dal processo biforcuto nello stesso modo in cui viene eseguito dalla console ?, cioè, basta inserire i dati attraverso senza buffering?

risposta

14

In generale, la libreria di runtime C standard (che funziona per conto di quasi tutti i programmi su tutti i sistemi, più o meno ;-) rileva se stdout è un terminale o meno; in caso contrario, buffer l'output (che può essere una grande vittoria di efficienza, rispetto all'output non bufferizzato).

Se hai il controllo del programma che sta scrivendo, puoi (come un'altra risposta suggerita) eseguire continuamente lo stdout, o (in modo più elegante se possibile) provare a forzare lo stdout per essere unbuffered, ad es. eseguendo Python con la bandiera -u riga di comando:

-u  : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x) 
     see man page for details on internal buffering relating to '-u' 

(ciò che la pagina man aggiunge è una menzione di stdin e problemi con modalità binaria [s]).

Se non si può o non si vuole toccare il programma che sta scrivendo, -u o simili sul programma che è solo la lettura è improbabile che aiuti (il buffering che conta di più è quello che accade sullo stdout dello scrittore, non quello sullo stdin del lettore). L'alternativa è ingannare lo scrittore facendogli credere che sta scrivendo su un terminale (anche se in realtà sta scrivendo su un altro programma!), Tramite il modulo libreria standard pty o il modulo di livello superiore di terze parti pexpect (o, per Windows, il suo porta wexpect).

+0

Ho provato a giocare con -u, nessuna gioia ma il pexpect sembra promettente, grazie! –

+0

solo per il follow up, pexpect funziona come un incantesimo, wexpect è un po 'buggato (e difficile da trovare) ma fa il lavoro. È qui che ho trovato la versione più recente di wexpect: http://sage.math.washington.edu/home/goreckc/sage/wexpect/ –

+0

Grazie a Gearoid, in particolare, che wexpect non è stato aggiornato all'ultima versione disponibile code.google.com a casa, mi chiedo perché! –

1

Questo è corretto e si applica a Windows e Linux (e possibilmente ad altri sistemi), con popen() e fopen(). Se si desidera che il buffer di output venga inviato prima di 4096 byte, utilizzare fflush() (su C) o sys.stdout.flush() (Python).

+0

Sì, questo è quello che sto facendo al momento, ma la mia situazione di lavoro significa che il processo che genera l'output è definito dall'utente, avrei dovuto menzionarlo nella domanda iniziale –

Problemi correlati