Пролить свет на работу с конвейерами и подпроцессами в Python? - PullRequest
2 голосов
/ 14 августа 2010

Я борюсь с концепциями подпроцессов и конвейеров и работаю с ними в контексте Python. Если бы кто-нибудь мог пролить свет на эти вопросы, это действительно помогло бы мне.

  1. Скажем, у меня конвейер настроен следующим образом

    createText.py | processText.py | cat

    processText.py получает данные через стандартный ввод, но как это реализовать? Откуда он знает, что больше не будет данных и что они должны выйти? Я предполагаю, что он может искать EOF и завершать его на основании этого, но что если createText.py никогда не отправит его? Будет ли это ошибкой со стороны createText.py?

  2. Скажем, parent.py запускает дочерний подпроцесс (child.py) и вызывает wait (), чтобы дождаться завершения дочернего процесса. Если parent записывает дочерние stdout и stderr в виде каналов, все еще безопасно читать их после завершения дочернего процесса? Или трубы (и данные в них) разрушаются, когда заканчивается один конец?

  3. Основная проблема, которую я хочу решить, - это написать скрипт на Python, который несколько раз вызывает rsync с классом Popen. Я хочу, чтобы моя программа ожидала завершения rsync, затем я хочу проверить состояние возврата, чтобы увидеть, правильно ли он вышел. Если это не так, я хочу прочитать stderr ребенка, чтобы увидеть, в чем была ошибка. Вот то, что я имею до сих пор

    # makes the rsync call.  Will block until the child
    # process is finished.  Returns the exit code for rsync
    def performRsync(src, dest):
        print "Pushing " + src + " to " + dest
        child = Popen(['rsync', '-av', src, dest], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        child.wait()    
        ## check for success or failure
        ## 0 is a successful exit code here
        if not child.returncode:
            return True 
        else:#ballz
            stout, sterr = child.communicate()
            print "ERR pushing " + src + ". " + sterr
            return False
    
  4. Обновление: я тоже сталкивался с этой проблемой. Рассмотрим два простых файла:

    # createText.py
    for x in range(1000):
        print "creating line " + str(x)
        time.sleep(1)
    
    # processText.py
    while True:
        line = sys.stdin.readline()
        if not line:
            break;
        print "I modified " + line
    

    Почему processText.py в этом случае не начинает печатать, так как получает данные из stdin? Собирает ли канал некоторое количество буферизованных данных перед тем, как передать их?

1 Ответ

1 голос
/ 14 августа 2010

Предполагается, что среда UNIXish / POSIXish.

EOF в конвейере сигнализируется отсутствием данных для чтения, то есть read() возвращает длину 0. Обычно это происходит, когда левая рукаПроцесс завершает работу и закрывает свой стандартный вывод.Поскольку вы не можете читать из канала, у которого другой конец закрыт, read в processText указывает на EOF.

Если createText не должен завершиться, закрывая свой вывод, это будет неконечная программа, которая втрубопровод плохая вещь.Даже если не в конвейере, программа, которая никогда не заканчивается, обычно некорректна (исключаются странные случаи, такие как yes(1)).

Вы можете читать из канала, пока вы не получите EOF или IOError (errno.EPIPE), который бы также указывал, что читать нечего.

У меня естьне проверял ваш код, он делает что-то неожиданное?

...