Python sous-processus readlines() se bloque
La tâche, j'ai essayer de faire est de diffuser un fichier ruby et imprimer le résultat. (NOTE: je ne veux pas imprimer tout à la fois)
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!"
Problème
Streaming le fichier fonctionne très bien. Le bonjour/au revoir de sortie est imprimée avec les 2 secondes de retard. Exactement comme le script devrait fonctionner. Le problème est que readline() se bloque à la fin, et jamais ne se ferme. Je n'ai jamais atteindre la dernière impression.
Je sais il y a beaucoup de questions de ce genre ici un stackoverflow mais non d'eux m'a permis de résoudre le problème. Je ne suis pas que dans l'ensemble du processus secondaire chose donc merci de me donner la main sur/réponse concrète.
Ce qui concerne
modifier
Fixer involontaire code. (rien à voir avec l'erreur réelle)
- Pas sûr si vous avez une erreur de saisie lors de coller le code dans votre question, ou si le problème est authentique. Me semble que le
if
doit être mis en retrait, de sorte qu'il est à l'intérieur de la boucle. - Merci pour remarquer. C'est une faute de frappe quand j'ai collé le code. C'est corrigé maintenant. Désolé à ce sujet.
- Je ne suis pas sûr, mais ce n'est pas votre problème très similaire à celle de la stackoverflow.com/questions/8495794/... ?
Vous devez vous connecter pour publier un commentaire.
Je suppose que vous utilisez
pty
pour des raisons décrites dans Q: Pourquoi ne pas utiliser un tuyau (popen())? (toutes les autres réponses ignorer votre "REMARQUE: je ne veux pas imprimer tout à la fois").pty
est seulement pour Linux comme dit dans la doc:Il est difficile de savoir comment cela fonctionne bien sur d'autres Systèmes d'exploitation.
Vous pouvez essayer de
pexpect
:Ou
stdbuf
pour activer la ligne de mise en mémoire tampon en mode non-interactif:Ou à l'aide de
pty
de stdlib basé sur @Antti de la Haapala réponse:Tous trois exemples de code print 'bonjour' immédiatement (dès la première fin de vie s'est vu).
de laisser les vieilles plus compliquée exemple de code ici, car il peut être référencé et discuté dans d'autres posts sur SO
Ou à l'aide de
pty
basé sur @Antti de la Haapala réponse:if not data: break
ici? ne serait-ce pas le cas d'être pris par laproc.poll() is not None
dans l'autre tandis que, d'itération?p.poll()
n'est pas utilisée pour briser la boucle dans le nouveau code (avecwhile 1
boucle). Connexes Python sous-processus .check_call vs .check_outputselect.select
il y a à distinguerstdout
destderr
. Les autres exemples de code ci-dessus ne fournissent pas cette capacité (dont nous avons besoin, car en général nous ne savons pas lequel des deux à le lire à partir de la première).Pas sûr de ce qui est erroné avec votre code, mais la suite semble fonctionner pour moi:
Noter que je n'ai pas de Ruby installé, et ne peut donc pas vérifier avec votre problème. Fonctionne très bien avec
ls
, si.if len(line):
est la paix qui m'aide. en utilisant seulementif line:
ne fonctionne pas sur python3.Fondamentalement, ce que vous voyez ici est une condition de course entre votre
proc.poll()
et votrereadline()
. Depuis l'entrée sur l'master
descripteur de fichier n'est jamais fermé, si le processus tente de faire unreadline()
après le rubis est terminé, la sortie, il n'y aura jamais rien à lire, mais le tuyau ne sera jamais comblé. Le code ne fonctionnera que si le processus de shell se ferme avant votre code d'essayer une autre readline().Voici la chronologie:
Solution facile est d'utiliser le sous-processus module comme il l'indique dans la doc, pas en liaison avec openpty:
http://docs.python.org/library/subprocess.html
Voici un problème similaire pour complément d'étude:
À l'aide de sous-processus avec les sélectionner et pty se bloque lors de la capture de la sortie
pty
, mais à l'aide dereadline
.pty
. Elle se trouve toujours dans readline. C'est seulement quand j'ai enlevé readline que le code a fonctionné.Essayez ceci:
Comme d'autres l'ont noté,
readline()
va bloquer lors de la lecture des données. Il va même jusqu'à le faire lorsque votre enfant est mort. Je ne suis pas sûr de savoir pourquoi cela ne se produit pas lors de l'exécution dels
comme dans l'autre réponse, mais peut-être que l'interpréteur ruby détecte qu'il est écrit pour une PIPE et, par conséquent, il ne fermera pas automatiquement.hello
avant le décès de l'enfant en raison de bloc-mise en mémoire tampon..readline()
dans votre cas, retourne''
lorsque le décès de l'enfant (essayer aveciter(proc.stdout.readline, b'')
).