J'ai un script nommé 1st.py
qui crée un REPL (read-eval-print-loop):
print "Something to print"
while True:
r = raw_input()
if r == 'n':
print "exiting"
break
else:
print "continuing"
J'ai ensuite lancé 1st.py
avec le code suivant:
p = subprocess.Popen(["python","1st.py"], stdin=PIPE, stdout=PIPE)
Et puis essayé ceci:
print p.communicate()[0]
Il a échoué, fournissant cette traceback:
Traceback (most recent call last):
File "1st.py", line 3, in <module>
r = raw_input()
EOFError: EOF when reading a line
Pouvez-vous expliquer ce qui se passe ici s'il vous plaît? Lorsque j'utilise p.stdout.read()
, il se bloque pour toujours.
.communicate()
écrit les entrées (il n'y a pas d'entrée dans ce cas, il ferme donc simplement le stdin du sous-processus pour indiquer au sous-processus qu'il n'y a plus d'entrées), lit toutes les sorties et attend la fin du sous-processus.
L'exception EOFError est générée dans le processus enfant par raw_input()
(les données attendues mais ont reçu EOF (pas de données)).
p.stdout.read()
est suspendu pour toujours car il essaie de lire la sortie all de l'enfant en même temps que l'enfant attend l'entrée (raw_input()
) qui provoque un blocage.
Pour éviter le blocage, vous devez lire/écrire de manière asynchrone (par exemple, en utilisant des fils ou sélectionnez) ou savoir exactement quand et combien de lecture/écriture, par exemple :
from subprocess import PIPE, Popen
p = Popen(["python", "-u", "1st.py"], stdin=PIPE, stdout=PIPE, bufsize=1)
print p.stdout.readline(), # read the first line
for i in range(10): # repeat several times to show that it works
print >>p.stdin, i # write input
p.stdin.flush() # not necessary in this case
print p.stdout.readline(), # read output
print p.communicate("n\n")[0], # signal the child to exit,
# read the rest of the output,
# wait for the child to exit
Remarque: le code est très fragile si les opérations de lecture/écriture ne sont pas synchronisées. ça bloque.
Méfiez-vous des problème de mise en mémoire tampon de blocs (ici, le problème est résolu en utilisant "-u" qui désactive la mise en mémoire tampon pour stdin, stdout dans l'enfant ).
bufsize=1
fait en sorte que les tuyaux soient mis en tampon de lignes du côté parent .
Ne pas utiliser communiquer (input = ""). Il écrit les entrées dans le processus, ferme son stdin et lit ensuite toutes les sorties.
Fais-le comme ça:
p=subprocess.Popen(["python","1st.py"],stdin=PIPE,stdout=PIPE)
# get output from process "Something to print"
one_line_output = p.stdout.readline()
# write 'a line\n' to the process
p.stdin.write('a line\n')
# get output from process "not time to break"
one_line_output = p.stdout.readline()
# write "n\n" to that process for if r=='n':
p.stdin.write('n\n')
# read the last output from the process "Exiting"
one_line_output = p.stdout.readline()
Que feriez-vous pour supprimer l'erreur:
all_the_process_will_tell_you = p.communicate('all you will ever say to this process\nn\n')[0]
Mais puisque communication ferme les variables stdout
et stdin
et stderr
, vous ne pouvez ni lire ni écrire après avoir appelé communiquer.
Votre deuxième bit de code commence le premier bit de code en tant que sous-processus avec une entrée et une sortie canalisées. Il ferme ensuite son entrée et essaie de lire sa sortie.
Le premier bit de code tente de lire à partir de l'entrée standard, mais le processus qui l'a démarré a fermé son entrée standard, de sorte qu'il atteint immédiatement une fin de fichier, que Python transforme en exception.