Intercepter la sortie standard d'un sous-processus pendant son exécution
-
22-08-2019 - |
Question
Si c'est mon sous-processus :
import time, sys
for i in range(200):
sys.stdout.write( 'reading %i\n'%i )
time.sleep(.02)
Et voici le script contrôlant et modifiant 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 est-ce readline
et communicate
attendre que le processus soit terminé ?Existe-t-il un moyen simple de transmettre (et de modifier) la sortie standard du sous-processus en temps réel ?
BTW, j'ai vu ce, mais je n'ai pas besoin des fonctionnalités de journalisation (et je n'ai pas pris la peine d'en comprendre grand-chose).
Je suis sous Windows XP.
La solution
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é de certains articles 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__)
Autres conseils
La sortie du processus est mise en mémoire tampon.Sur davantage de systèmes d'exploitation UNIXy (ou Cygwin), le je m'attends Un module 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 travail module pty, qui n'est pas disponible sur les versions Python win32 natives (non cygwin).
Dans le cas d'exemple où vous contrôlez le sous-processus, vous pouvez simplement le faire appeler sys.stdout.flush()
si nécessaire - mais pour les sous-processus arbitraires, cette option n'est pas disponible.
Voir également la question "Pourquoi ne pas simplement utiliser un tube (popen()) ?" dans la FAQ pexpect.