visual studio microsoft español descargar community python subprocess

python - microsoft - visual studio installer



Las líneas de lectura del subproceso Python() se cuelgan (4)

La tarea que intento lograr es transmitir un archivo ruby ​​e imprimir el resultado. ( NOTA : no quiero imprimir todo de una vez)

main.py

from subprocess import Popen, PIPE, STDOUT import pty import os file_path = ''/Users/luciano/Desktop/ruby_sleep.rb'' command = '' ''.join(["ruby", file_path]) master, slave = pty.openpty() proc = Popen(command, bufsize=0, shell=True, stdout=slave, stderr=slave, close_fds=True) stdout = os.fdopen(master, ''r'', 0) while proc.poll() is None: data = stdout.readline() if data != "": print(data) else: break print("This is never reached!")

ruby_sleep.rb

puts "hello" sleep 2 puts "goodbye!"

Problema

Transmitir el archivo funciona bien. La salida de saludo / despedida se imprime con la demora de 2 segundos. Exactamente como el script debería funcionar. El problema es que readline () se cuelga al final y nunca se cierra. Nunca alcanzo la última impresión.

Sé que hay muchas preguntas como esta aquí un stackoverflow pero ninguna de ellas me hizo resolver el problema. No estoy tan metido en todo el subproceso así que por favor dame una respuesta más práctica / concreta.

Saludos

editar

Repara el código no deseado. (nada que ver con el error real)


No estoy seguro de lo que está mal con su código, pero lo siguiente parece funcionar para mí:

#!/usr/bin/python from subprocess import Popen, PIPE import threading p = Popen(''ls'', stdout=PIPE) class ReaderThread(threading.Thread): def __init__(self, stream): threading.Thread.__init__(self) self.stream = stream def run(self): while True: line = self.stream.readline() if len(line) == 0: break print line, reader = ReaderThread(p.stdout) reader.start() # Wait until subprocess is done p.wait() # Wait until we''ve processed all output reader.join() print "Done!"

Tenga en cuenta que no tengo instalado Ruby y, por lo tanto, no puedo verificar su problema real. Funciona bien con ls , sin embargo.


Prueba esto:

proc = Popen(command, bufsize=0, shell=True, stdout=PIPE, close_fds=True) for line in proc.stdout: print line print("This is most certainly reached!")

Como otros han notado, readline() se bloqueará al leer datos. Incluso lo hará cuando el proceso de su hijo haya muerto. No estoy seguro de por qué esto no ocurre al ejecutar ls como en la otra respuesta, pero tal vez el intérprete de ruby ​​detecta que está escribiendo en un PIPE y por lo tanto no se cierra automáticamente.


Básicamente, lo que estás viendo aquí es una condición de carrera entre tu proc.poll() y tu readline() . Como la entrada en la manejador de archivos master nunca se cierra, si el proceso intenta hacer una línea de readline() después de que el proceso de ruby ​​haya terminado de salir, nunca habrá nada que leer, pero la tubería nunca se cerrará. El código solo funcionará si el proceso de shell se cierra antes de que su código pruebe otra readline ().

Aquí está la línea de tiempo:

readline() print-output poll() readline() print-output (last line of real output) poll() (returns false since process is not done) readline() (waits for more output) (process is done, but output pipe still open and no poll ever happens for it).

Una solución fácil es simplemente usar el módulo de subproceso como sugiere en los documentos, no junto con openpty:

http://docs.python.org/library/subprocess.html

Aquí hay un problema muy similar para un estudio posterior:

Usar subproceso con select y pty cuelga cuando se captura la salida


Supongo que usa pty por los motivos descritos en P: ¿Por qué no utiliza una pipa (popen ())? (todas las otras respuestas hasta el momento ignoran su "NOTA: no quiero imprimir todo de una vez" ).

pty es Linux solo como se dice en los documentos :

Como el manejo de pseudo-terminales depende en gran medida de la plataforma, hay un código para hacerlo solo para Linux. (Se supone que el código de Linux funciona en otras plataformas, pero aún no se ha probado).

No está claro qué tan bien funciona en otros sistemas operativos.

Podrías probar pexpect :

import sys import pexpect pexpect.run("ruby ruby_sleep.rb", logfile=sys.stdout)

O stdbuf para habilitar el almacenamiento de líneas en modo no interactivo:

from subprocess import Popen, PIPE, STDOUT proc = Popen([''stdbuf'', ''-oL'', ''ruby'', ''ruby_sleep.rb''], bufsize=1, stdout=PIPE, stderr=STDOUT, close_fds=True) for line in iter(proc.stdout.readline, b''''): print line, proc.stdout.close() proc.wait()

O usando pty de stdlib basado en la respuesta de @Antti Haapala :

#!/usr/bin/env python import errno import os import pty from subprocess import Popen, STDOUT master_fd, slave_fd = pty.openpty() # provide tty to enable # line-buffering on ruby''s side proc = Popen([''ruby'', ''ruby_sleep.rb''], stdin=slave_fd, stdout=slave_fd, stderr=STDOUT, close_fds=True) os.close(slave_fd) try: while 1: try: data = os.read(master_fd, 512) except OSError as e: if e.errno != errno.EIO: raise break # EIO means EOF on some systems else: if not data: # EOF break print(''got '' + repr(data)) finally: os.close(master_fd) if proc.poll() is None: proc.kill() proc.wait() print("This is reached!")

Los tres ejemplos de código imprimen ''hola'' inmediatamente (tan pronto como se ve el primer EOL).

deje aquí el ejemplo del código anterior más complicado porque puede ser referenciado y discutido en otras publicaciones en SO

O usando pty basado en la respuesta de @Antti Haapala :

import os import pty import select from subprocess import Popen, STDOUT master_fd, slave_fd = pty.openpty() # provide tty to enable # line-buffering on ruby''s side proc = Popen([''ruby'', ''ruby_sleep.rb''], stdout=slave_fd, stderr=STDOUT, close_fds=True) timeout = .04 # seconds while 1: ready, _, _ = select.select([master_fd], [], [], timeout) if ready: data = os.read(master_fd, 512) if not data: break print("got " + repr(data)) elif proc.poll() is not None: # select timeout assert not select.select([master_fd], [], [], 0)[0] # detect race condition break # proc exited os.close(slave_fd) # can''t do it sooner: it leads to errno.EIO error os.close(master_fd) proc.wait() print("This is reached!")