Die Verwendung des Unterprozesses mit select und pty bleibt beim Erfassen der Ausgabe hängen

Ich versuche, ein Python-Programm zu schreiben, das mit anderen Programmen interagieren kann. Das bedeutet stdin senden und stdout Daten empfangen. Ich kann pexpect nicht verwenden (obwohl es definitiv einen Teil des Designs inspiriert hat). Der Prozess, den ich gerade benutze, ist der folgende:

Fügen Sie der Standardausgabe des Unterprozesses ein Pty hinzuSchleife, bis der Unterprozess durch Überprüfen beendet wirdsubprocess.pollWenn Daten in der Standardausgabe verfügbar sind, schreiben Sie diese Daten sofort in die aktuelle Standardausgabe.Fertig!

Ich habe einen Code (unten) als Prototyp erstellt, der funktioniert, aber einen Fehler zu haben scheint, der mich nervt. Nach Abschluss des untergeordneten Prozesses bleibt der übergeordnete Prozess hängen, wenn bei der Verwendung kein Zeitlimit angegeben wirdselect.select. Ich würde es wirklich vorziehen, kein Timeout festzulegen. Es scheint nur ein bisschen schmutzig. Alle anderen Methoden, mit denen ich versucht habe, das Problem zu umgehen, scheinen jedoch nicht zu funktionieren. Pexpect scheint es zu umgehen, indem es verwendetos.execv undpty.fork anstattsubprocess.Popen undpty.openpty eine lösung ziehe ich nicht vor. Mache ich etwas falsch mit der Überprüfung der Lebensdauer des Subprozesses? Ist mein Ansatz falsch?

Der Code, den ich benutze, ist unten. Ich verwende dies auf einem Mac OS X 10.6.8, aber ich brauche es auch, um mit Ubuntu 12.04 zu arbeiten.

Dies ist der Subprozess-Runnerrunner.py:

import subprocess
import select
import pty
import os
import sys

def main():
    master, slave = pty.openpty()

    process = subprocess.Popen(['python', 'outputter.py'], 
            stdin=subprocess.PIPE, 
            stdout=slave, stderr=slave, close_fds=True)

    while process.poll() is None:
        # Just FYI timeout is the last argument to select.select
        rlist, wlist, xlist = select.select([master], [], [])
        for f in rlist:
            output = os.read(f, 1000) # This is used because it doesn't block
            sys.stdout.write(output)
            sys.stdout.flush()
    print "**ALL COMPLETED**"

if __name__ == '__main__':
    main()

Dies ist der Unterprozesscodeoutputter.py. Die seltsamen zufälligen Teile simulieren lediglich ein Programm, das Daten in zufälligen Intervallen ausgibt. Sie können es entfernen, wenn Sie möchten. Es sollte keine Rolle spielen:

import time
import sys
import random

def main():
    lines = ['hello', 'there', 'what', 'are', 'you', 'doing']
    for line in lines:
        sys.stdout.write(line + random.choice(['', '\n']))
        sys.stdout.flush()
        time.sleep(random.choice([1,2,3,4,5])/20.0)
    sys.stdout.write("\ndone\n")
    sys.stdout.flush()

if __name__ == '__main__':
    main()

Vielen Dank für jede Hilfe, die Sie alle leisten können!

Zusätzlicher Hinweis

pty wird verwendet, weil ich sicherstellen möchte, dass stdout nicht gepuffert wird.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage