2012-05-02 20 views
5

Tengo algunas dificultades para obtener resultados de una tubería de subproceso stdout. Estoy lanzando un código de terceros a través de él, para extraer la salida de registro. Hasta una actualización reciente del código de un tercero, todo funcionó bien. Después de la actualización, Python ha comenzado a bloquear de forma indefinida y no muestra ningún resultado. Puedo iniciar manualmente la aplicación de terceros y ver resultados.Salida del subproceso Python en Windows?

Una versión básica del código que estoy usando:

import subprocess, time 
from threading import Thread 

def enqueue_output(out): 
    print "Hello from enqueue_output" 
    for line in iter(out.readline,''): 
     line = line.rstrip("\r\n") 
     print "Got %s" % line 
    out.close() 

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1) 
thread = Thread(target=enqueue_output, args=(proc.stdout,)) 
thread.daemon = True 
thread.start() 

time.sleep(30) 

Esto funciona perfectamente si sustituyo third_party.exe para este script:

import time, sys 

while True: 
    print "Test" 
    sys.stdout.flush() 
    time.sleep(1) 

Así que estoy claro en cuanto a la magia debe hacerse para que esto funcione con el comando original.

Estas son todas las variantes de la línea subprocess.Popen que he probado sin éxito:

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=0) 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, shell=True) 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, creationflags=subprocess.CREATE_NEW_CONSOLE) 
si = subprocess.STARTUPINFO() 
si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, startupinfo=si) 

Edición 1: no puedo utilizar realmente .communicate() en este caso. La aplicación que estoy lanzando sigue ejecutándose durante largos períodos de tiempo (días o semanas). La única forma en que podría probar .communicate() sería matar la aplicación poco después de su lanzamiento, lo que no creo que me daría resultados válidos.

Incluso la versión no roscada de esta falla:

import subprocess, time 
from threading import Thread 

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

print "App started, reading output..." 
for line in iter(proc.stdout.readline,''): 
    line = line.rstrip("\r\n") 
    print "Got: %s" % line 

Edición 2: Gracias a jdi, las siguientes obras okay:

import tempfile, time, subprocess 

w = "test.txt" 
f = open("test.txt","a") 
p = subprocess.Popen("third_party.exe", shell=True, stdout=f, 
         stderr=subprocess.STDOUT, bufsize=0) 

time.sleep(30) 

with open("test.txt", 'r') as r: 
    for line in r: 
     print line 
f.close() 
+0

¿Es posible que su programa de terceros haya cambiado a la escritura en stderr? – jdi

+0

No parece ser el caso. Si intercepto stderr, sucede lo mismo (aunque veo la salida de la aplicación en la consola, pero solo imprime, no está pasando por Python). – devicenull

+0

Parece que la aplicación ha dejado de usar la salida estándar y está escribiendo directamente en la consola. Si es así, no hay mucho que puedas hacer al respecto. ¿Puedes consultar con el proveedor de la aplicación? –

Respuesta

5

En primer lugar, recomiendo que a simplificar este ejemplo para asegurarte de que realmente puedes leer cualquier cosa Elimine la complicación del hilo de la mezcla:

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1) 
print proc.communicate() 

Si eso funciona, genial. Entonces está teniendo problemas posiblemente con la forma en que está leyendo el stdout directamente o posiblemente en su hilo.

Si esto no funciona, ¿ha intentado conectar stderr a stdout también?

proc = subprocess.Popen("third_party.exe", 
         stdout=subprocess.PIPE, 
         stderr=subprocess.STDOUT, bufsize=1) 

actualización

Dado que usted dice communicate() se DEADLOCKING, aquí es otro enfoque puede probar para ver si es un problema con el tampón interna del subproceso ...

import tempfile 
import subprocess 

w = tempfile.NamedTemporaryFile() 
p = subprocess.Popen('third_party.exe', shell=True, stdout=w, 
         stderr=subprocess.STDOUT, bufsize=0) 

with open(w.name, 'r') as r: 
    for line in r: 
     print line 
w.close() 
+0

Si tuve un error con el hilo, ¿por qué funcionaría para mi aplicación de prueba simple, pero no es la real? No puedo usar la comunicación, ya que la aplicación no termina en realidad. Es un servidor y se mantiene funcionando durante largos períodos de tiempo. – devicenull

+0

@devicenull: Diría que la diferencia es que el script de prueba está imprimiendo 4 caracteres, lentamente, cada segundo, mientras que no tengo idea de qué tipo de salida está haciendo su aplicación de terceros. Podrías estar bloqueando el buffer. Además, cuando tiene problemas como este, siempre es mejor eliminar tantas variables como sea posible y asegurarse de que cada paso funcione correctamente. – jdi

+0

La salida a un archivo funciona perfectamente. ¿Alguna idea de por qué funciona, pero las tuberías no? – devicenull

2
args = ['svn','log','-v'] 

def foo(info=''): 
    import logging 
    import subprocess 
    import tempfile 
    try: 
     pipe = subprocess.Popen(args,bufsize = 0,\ 
      stdout = subprocess.PIPE,\ 
      stderr=subprocess.STDOUT) 
    except Exception as e: 
     logging.error(str(e)) 
     return False 
    while 1: 
     s = pipe.stdout.read() 
     if s: 
      print s, 
     if pipe.returncode is None: 
      pipe.poll() 
     else: 
      break 
    if not 0 == pipe.returncode: 
     return False 
    return True 

print foo() 

Este debería funcionar, no enhebrar, archivo temporal mágico.

Cuestiones relacionadas