Używanie podprocesu z select i pty zawiesza się podczas przechwytywania danych wyjściowych

Próbuję napisać program python, który jest w stanie współdziałać z innymi programami. Oznacza to wysyłanie standardowego wejścia i otrzymywanie danych standardowych. Nie mogę używać pexpect (choć na pewno zainspirowało to część projektu). Obecnie używam tego procesu:

Dołącz pty do stdout podprocesuPętla, aż podproces zakończy działanie, sprawdzającsubprocess.pollGdy dostępne są dane w stdout, zapisz te dane natychmiast w bieżącym stdout.Koniec!

Prototypowałem jakiś kod (poniżej), który działa, ale wydaje się, że ma jedną wadę, która mnie dręczy. Po zakończeniu procesu potomnego proces nadrzędny zawiesza się, jeśli nie określę limitu czasu podczas używaniaselect.select. Naprawdę wolałbym nie ustawiać limitu czasu. To wydaje się trochę brudne. Jednak wszystkie inne sposoby, które próbowałem obejść, nie działają. Wydaje się, że Pexpect omija to, używającos.execv ipty.fork zamiastsubprocess.Popen ipty.openpty rozwiązanie, którego nie preferuję. Czy robię coś złego z tym, jak sprawdzam życie podprocesu? Czy moje podejście jest nieprawidłowe?

Kod, którego używam, znajduje się poniżej. Używam tego na Mac OS X 10.6.8, ale potrzebuję go także do pracy z Ubuntu 12.04.

To jest podprocesorrunner.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()

To jest kod podprocesuoutputter.py. Dziwne losowe części służą jedynie do symulowania programu, który wysyła dane w losowych odstępach czasu. Możesz go usunąć, jeśli chcesz. To nie powinno mieć znaczenia:

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()

Dziękujemy za wszelką pomoc, którą wszyscy możecie zapewnić!

Dodatkowa uwaga

pty jest używany, ponieważ chcę mieć pewność, że stdout nie jest buforowany.

questionAnswers(4)

yourAnswerToTheQuestion