Nessuna delle risposte qui ha risposto a tutte le mie esigenze.
- Nessun thread per stdout (nessuna coda, ecc.)
- Non bloccante in quanto ho bisogno di controllare altre cose in corso
- Usa PIPE come avevo bisogno per fare più cose, ad esempio l'output di flusso, scrivere in un file di registro e restituire una copia stringa dell'output.
Un po 'di storia: sto usando un ThreadPoolExecutor per gestire un pool di thread, ognuno dei quali avvia un sottoprocesso ed esegue la concorrenza. (In Python2.7, ma dovrebbe funzionare anche con la versione 3.x più recente). Non voglio usare i thread solo per la raccolta dell'output poiché ne voglio quanti più disponibili possibile per altre cose (un pool di 20 processi userebbe 40 thread solo per essere eseguito; 1 per il thread del processo e 1 per stdout ... e altro se vuoi stderr immagino)
Sto eliminando molte eccezioni e simili qui quindi questo si basa sul codice che funziona in produzione. Spero di non averlo rovinato nella copia e incolla. Inoltre, feedback molto gradito!
import time
import fcntl
import subprocess
import time
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Make stdout non-blocking when using read/readline
proc_stdout = proc.stdout
fl = fcntl.fcntl(proc_stdout, fcntl.F_GETFL)
fcntl.fcntl(proc_stdout, fcntl.F_SETFL, fl | os.O_NONBLOCK)
def handle_stdout(proc_stream, my_buffer, echo_streams=True, log_file=None):
"""A little inline function to handle the stdout business. """
# fcntl makes readline non-blocking so it raises an IOError when empty
try:
for s in iter(proc_stream.readline, ''): # replace '' with b'' for Python 3
my_buffer.append(s)
if echo_streams:
sys.stdout.write(s)
if log_file:
log_file.write(s)
except IOError:
pass
# The main loop while subprocess is running
stdout_parts = []
while proc.poll() is None:
handle_stdout(proc_stdout, stdout_parts)
# ...Check for other things here...
# For example, check a multiprocessor.Value('b') to proc.kill()
time.sleep(0.01)
# Not sure if this is needed, but run it again just to be sure we got it all?
handle_stdout(proc_stdout, stdout_parts)
stdout_str = "".join(stdout_parts) # Just to demo
Sono sicuro che ci sia un sovraccarico da aggiungere qui, ma non è un problema nel mio caso. Funzionalmente fa quello che mi serve. L'unica cosa che non ho risolto è il motivo per cui questo funziona perfettamente per i messaggi di registro, ma vedo alcuni print
messaggi apparire più tardi e tutti in una volta.