2009-02-09 6 views
21

Si ceci est mon sous-processus:Intercepter stdout d'un sous-processus en cours d'exécution

import time, sys 
for i in range(200): 
    sys.stdout.write('reading %i\n'%i) 
    time.sleep(.02) 

Et c'est le script de contrôle et de modification de la sortie du sous-processus:

import subprocess, time, sys 

print 'starting' 

proc = subprocess.Popen(
    'c:/test_apps/testcr.py', 
    shell=True, 
    stdin=subprocess.PIPE, 
    stdout=subprocess.PIPE ) 

print 'process created' 

while True: 
    #next_line = proc.communicate()[0] 
    next_line = proc.stdout.readline() 
    if next_line == '' and proc.poll() != None: 
     break 
    sys.stdout.write(next_line) 
    sys.stdout.flush() 

print 'done' 

Pourquoi readline et communicate attendre jusqu'à ce que le processus soit terminé? Existe-t-il un moyen simple de passer (et de modifier) ​​le sous-processus 'stdout' en temps réel? Par ailleurs, j'ai vu this, mais je n'ai pas besoin des fonctionnalités de journalisation (et je n'ai pas vraiment compris).

Je suis sous Windows XP.

+0

connexes: [? Comment vider la sortie de l'impression Python] (http://stackoverflow.com/q/230751/95735) –

Répondre

14

Comme Charles l'a déjà mentionné, le problème est la mise en mémoire tampon. J'ai rencontré un problème similaire lors de l'écriture de certains modules pour SNMPd, et je l'ai résolu en remplaçant stdout par une version à vidage automatique.

J'ai utilisé le code suivant, inspiré par quelques messages sur ActiveState:

class FlushFile(object): 
    """Write-only flushing wrapper for file-type objects.""" 
    def __init__(self, f): 
     self.f = f 
    def write(self, x): 
     self.f.write(x) 
     self.f.flush() 

# Replace stdout with an automatically flushing version 
sys.stdout = FlushFile(sys.__stdout__) 
+0

Je ne vois pas comment c'est différent d'appeler sys.stdout.flush() après chaque sys.stdout.readline(), ce que je fais. J'ai également essayé de définir bufsize = 0 pour le sous-processus. – Paul

+9

Le vidage est nécessaire dans le sous-processus, pas dans le processus parent. – bobince

+0

Oui, dans l'exemple, le sous-processus est également un script python. Remplacez donc stdout dans le sous-processus. L'appel de sys.stdout.flush() dans le processus parent ne fait rien. –

7

La sortie du processus est mise en mémoire tampon. Sur plus de systèmes d'exploitation UNIXy (ou Cygwin), le module pexpect est disponible, qui récite toutes les incantations nécessaires pour éviter les problèmes liés à la mise en mémoire tampon. Cependant, ces incantations nécessitent un fonctionnement pty module, qui n'est pas disponible sur les builds Python win32 natives (non-cygwin).

Dans le cas de l'exemple où vous contrôlez le sous-processus, vous pouvez simplement l'appeler sys.stdout.flush() si nécessaire - mais pour les sous-processus arbitraires, cette option n'est pas disponible. Voir également the question "Why not just use a pipe (popen())?" dans la FAQ pexpect.

Questions connexes