web-dev-qa-db-fra.com

Comment obtenir la sortie de subprocess.Popen (). proc.stdout.readline () bloque, aucune donnée ne s'imprime

Je veux la sortie de Exécuter Test_Pipe.py, j'ai essayé de suivre le code sous Linux mais cela n'a pas fonctionné.

Test_Pipe.py

import time
while True :
    print "Someting ..."
    time.sleep(.1)

Caller.py

import subprocess as subp
import time

proc = subp.Popen(["python", "Test_Pipe.py"], stdout=subp.PIPE, stdin=subp.PIPE)

while True :
    data = proc.stdout.readline() #block / wait
    print data
    time.sleep(.1)

La ligne proc.stdout.readline() a été bloquée, donc aucune donnée ne s'imprime.

38
wearetherock

Vous pouvez évidemment utiliser subprocess.communicate mais je pense que vous recherchez une entrée et une sortie en temps réel.

readline a été bloquée car le processus attend probablement votre entrée. Vous pouvez lire caractère par caractère pour surmonter ce problème comme suit:

import subprocess
import sys

process = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

while True:
    out = process.stdout.read(1)
    if out == '' and process.poll() != None:
        break
    if out != '':
        sys.stdout.write(out)
        sys.stdout.flush()
44
Nadia Alramli

L'extrait de Nadia fonctionne, mais appeler read avec un tampon de 1 octet est fortement déconseillé. La meilleure façon de procéder serait de définir le descripteur de fichier stdout sur nonblocking en utilisant fcntl

fcntl.fcntl(
    proc.stdout.fileno(),
    fcntl.F_SETFL,
    fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
)

puis en utilisant select pour tester si les données sont prêtes

while proc.poll() == None:
    readx = select.select([proc.stdout.fileno()], [], [])[0]
    if readx:
        chunk = proc.stdout.read()
        print chunk

Elle avait raison en ce que votre problème doit être différent de ce que vous avez publié en tant que Caller.py et Test_Pipe.py fonctionnent comme prévu.

21
Derrick Petzold

Test_Pipe.py Met en mémoire tampon sa sortie standard par défaut afin que proc dans Caller.py Ne voit aucune sortie tant que le tampon de l'enfant n'est pas plein (si la taille du tampon est de 8 Ko, cela prend environ une minute pour remplir le tampon stdout de Test_Pipe.py).

Pour rendre la sortie non tamponnée (mise en mémoire tampon pour les flux de texte), vous pouvez passer indicateur -u à l'enfant Python. Il permet de lire le sous-processus 'sortie ligne par ligne en "temps réel":

import sys
from subprocess import Popen, PIPE

proc = Popen([sys.executable, "-u", "Test_Pipe.py"], stdout=PIPE, bufsize=1)
for line in iter(proc.stdout.readline, b''):
    print line,
proc.communicate()

Voir les liens dans Python: lire les entrées de streaming de subprocess.communicate () sur la façon de résoudre le problème de mise en mémoire tampon des blocs pour les processus enfants non Python.

14
jfs

Pour éviter les nombreux problèmes qui peuvent toujours survenir avec la mise en mémoire tampon pour des tâches telles que "obtenir la sortie du sous-processus vers le processus principal en temps réel", je recommande toujours d'utiliser pexpect pour toutes les plates-formes non Windows, - wexpect sous Windows, au lieu de subprocess, lorsque de telles tâches sont souhaitées.

13
Alex Martelli