2009-02-09 33 views
21

Si este es mi subproceso:La interceptación de la salida estándar de un subproceso mientras se está ejecutando

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

Y este es el guión controlar y modificar la salida del subproceso:

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' 

¿Por qué es readline y communicate esperando hasta que el proceso termine de ejecutarse? ¿Hay una manera simple de pasar (y modificar) el subproceso 'stdout en tiempo real?

Por cierto, he visto this, pero no necesito las características de registro (y no me he molestado en comprenderlo en gran parte).

Estoy en Windows XP.

+0

relacionadas: [? Cómo limpiar la salida de impresión Python] (http://stackoverflow.com/q/230751/95735) –

Respuesta

14

Como ya mencioné Charles, el problema es el almacenamiento en búfer. Me encontré con un problema similar al escribir algunos módulos para SNMPd, y lo resolví reemplazando stdout con una versión de limpieza automática.

He utilizado el siguiente código, inspirado en algunos de los puestos de 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

No veo cómo eso es diferente de llamar a sys.stdout.flush() después de cada sys.stdout.readline(), que es lo que hago. También intenté configurar bufsize = 0 para el subproceso. – Paul

+9

La descarga se necesita en el subproceso, no en el proceso principal. – bobince

+0

Sí, en el ejemplo, el subproceso también es un script de python. Entonces reemplace el stdout en el subproceso. Llamar a sys.stdout.flush() en el proceso principal no hace nada. –

7

La salida del proceso está almacenada en el búfer. En más sistemas operativos UNIXy (o Cygwin), el módulo pexpect está disponible, que recita todos los conjuros necesarios para evitar problemas relacionados con el almacenamiento en búfer. Sin embargo, estos encantamientos requieren un trabajo pty module, que no está disponible en versiones Win32 Python nativas (no cygwin).

En el caso de ejemplo donde usted controla el subproceso, puede simplemente hacer que llame al sys.stdout.flush() donde sea necesario, pero para subprocesos arbitrarios, esa opción no está disponible.

Consulte también the question "Why not just use a pipe (popen())?" en las preguntas frecuentes de pexpect.

Cuestiones relacionadas