example - ¿Cómo recupero la información ''en tiempo real'' de un subproceso? Pobre en Python(2.5)
subprocess python 3 example (10)
Me gustaría utilizar el módulo de subproceso de la siguiente manera:
- crea un nuevo proceso que potencialmente toma mucho tiempo para ejecutarse.
- capture
stdout
(ostderr
, o potencialmente ambos, juntos o por separado) - Procese los datos del subproceso tal como viene, tal vez disparando eventos en cada línea recibida (en wxPython decir) o simplemente imprimiéndolos por el momento.
Creé procesos con Popen, pero si uso comunicar () los datos me llegan a todos al mismo tiempo, una vez que el proceso ha finalizado.
Si creo un hilo separado que hace una línea de myprocess.stdout
de bloqueo readline()
de myprocess.stdout
(usando stdout = subprocess.PIPE
) tampoco obtengo ninguna línea con este método, hasta que el proceso finaliza. (no importa lo que configuro como bufsize)
¿Hay alguna forma de lidiar con esto que no sea horrible y que funcione bien en múltiples plataformas?
Actualiza con código que parece no funcionar (en Windows de todos modos)
class ThreadWorker(threading.Thread):
def __init__(self, callable, *args, **kwargs):
super(ThreadWorker, self).__init__()
self.callable = callable
self.args = args
self.kwargs = kwargs
self.setDaemon(True)
def run(self):
try:
self.callable(*self.args, **self.kwargs)
except wx.PyDeadObjectError:
pass
except Exception, e:
print e
if __name__ == "__main__":
import os
from subprocess import Popen, PIPE
def worker(pipe):
while True:
line = pipe.readline()
if line == '''': break
else: print line
proc = Popen("python subprocess_test.py", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout_worker = ThreadWorker(worker, proc.stdout)
stderr_worker = ThreadWorker(worker, proc.stderr)
stdout_worker.start()
stderr_worker.start()
while True: pass
Esta parece ser una limitación bien conocida de Python, vea PEP 3145 y tal vez otros.
Esto es lo que funcionó para mí:
cmd = ["./tester_script.bash"]
p = subprocess.Popen( cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
while p.poll() is None:
out = p.stdout.readline()
do_something_with( out, err )
En su caso, podría intentar pasar una referencia al subproceso a su Subproceso de trabajo, y realizar la votación dentro del subproceso. No sé cómo se comportará cuando dos subprocesos sondean (e interactúan) el mismo subproceso, pero puede funcionar.
También tenga en cuenta que el while p.poll() is None:
está destinado como está. No lo reemplace con while not p.poll()
como en python 0
(el código de retorno para la finalización exitosa) también se considera False
.
He usado el módulo pexpect para esto, parece funcionar bien. http://sourceforge.net/projects/pexpect/
Lee un personaje a la vez: http://blog.thelinuxkid.com/2013/06/get-python-subprocess-output-without.html
import contextlib
import subprocess
# Unix, Windows and old Macintosh end-of-line
newlines = [''/n'', ''/r/n'', ''/r'']
def unbuffered(proc, stream=''stdout''):
stream = getattr(proc, stream)
with contextlib.closing(stream):
while True:
out = []
last = stream.read(1)
# Don''t loop forever
if last == '''' and proc.poll() is not None:
break
while last not in newlines:
# Don''t loop forever
if last == '''' and proc.poll() is not None:
break
out.append(last)
last = stream.read(1)
out = ''''.join(out)
yield out
def example():
cmd = [''ls'', ''-l'', ''/'']
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
# Make all end-of-lines ''/n''
universal_newlines=True,
)
for line in unbuffered(proc):
print line
example()
Me he encontrado con este problema también. El problema ocurre porque también estás tratando de leer stderr. Si no hay errores, entonces tratar de leer desde stderr bloquearía.
En Windows, no hay una forma fácil de sondear los descriptores de archivos (solo los sockets de Winsock).
Entonces, una solución es no intentar leer de stderr.
Parece que el problema podría ser el uso de la salida almacenada en el subproceso; si se crea una cantidad relativamente pequeña de salida, podría almacenarse en el búfer hasta que salga el subproceso. Algunos antecedentes se pueden encontrar here :
Usar pexpect [ http://www.noah.org/wiki/Pexpect] con readlines sin bloqueo resolverá este problema. Se deriva del hecho de que las tuberías están almacenadas en un buffer, por lo que la salida de la aplicación está siendo amortiguada por la tubería, por lo tanto, no se puede acceder a esa salida hasta que se llene la memoria intermedia o el proceso se muera.
Utilizando el subproceso.Popen, puedo ejecutar el .exe de uno de mis proyectos C # y redireccionar el resultado a mi archivo Python. Ahora puedo print()
toda la información que se envía a la consola C # (usando Console.WriteLine()
) a la consola de Python.
Código de Python:
from subprocess import Popen, PIPE, STDOUT
p = Popen(''ConsoleDataImporter.exe'', stdout = PIPE, stderr = STDOUT, shell = True)
while True:
line = p.stdout.readline()
print(line)
if not line:
break
Esto obtiene la salida de la consola de mi proyecto .NET línea por línea a medida que se crea y sale del bucle while mientras se termina el proyecto. Me imagino que esto también funcionaría para dos archivos de Python.
stdout se almacenará en el búfer, por lo que no obtendrá nada hasta que se llene ese búfer, o el subproceso salga.
Puede intentar eliminar el stdout
del subproceso, o usar stderr, o cambiar el stdout en el modo sin búfer.