Вызов os.fsync для файловых дескрипторов stdout / stderr убивает подпроцесс - PullRequest
3 голосов
/ 15 июля 2011

После запуска подпроцесса с использованием библиотеки Python subprocess я использую stderr для передачи сообщения от дочернего процесса к родительскому процессу, содержащему некоторые сериализованные данные. Затем я хочу, чтобы родитель возвратил (через stdin) результат функции, примененной к этим данным.

По сути, у меня внутри подпроцесса есть функция, которая делает что-то вроде этого:

sys.stderr.write("some stuff to write")
# some time later
some_var = sys.stdin.read()

Однако, это завершает блокировки родительского элемента в ожидании ввода stderr, поэтому я попытался вызвать:

sys.stderr.flush()
os.fsync(sys.stderr.fileno())

Однако это не работает. Ничего после os.fsync не выполняется. Кроме того, когда я вызываю proc.poll() в родительском процессе, получается, что дочерний код возврата равен 1.

Что я могу сделать, чтобы предотвратить это? Должен ли я рассмотреть другой подход?

Ответы [ 2 ]

2 голосов
/ 15 июля 2011

Я бы рассмотрел другой подход.Вы можете использовать независимый процесс (multiprocessing.Process) и использовать две очереди для связи с ним (multiprocessing.Queue): одну для ввода и другую для вывода.Пример запуска процесса:

import multiprocessing

def processWorker(input, result):
    work = input.get()
    print work
    result.put(work*work)

input  = multiprocessing.Queue()
result = multiprocessing.Queue()

p = multiprocessing.Process(target = processWorker, args = (input, result))
p.start()

input.put(2)
res = result.get(block = True)
print res

Затем вы можете повторить его повторную передачу.Использование многопроцессорной обработки. Queue более устойчив, поскольку вам не нужно полагаться на разбор stdout / err, а также избегаете связанных ограничений.Более того, вы можете легко управлять большим количеством подпроцессов.

Затем вы также можете установить тайм-аут на то, как долго вы хотите, чтобы вызов get ожидал на максимуме, например:

import queue
try:
    res = result.get(block = True, timeout = 10)
except Queue.Empty:
    print error
1 голос
/ 15 июля 2011

Вот как вы можете предотвратить тупик ввода / вывода без радикального изменения подхода. У ребенка:

import os, fcntl
map(lambda f: fcntl.fcntl(f.fileno(), fcntl.F_SETFL, os.O_NONBLOCK),
    (sys.stdin, sys.stdout, sys.stderr))

В родительском объекте сделайте то же самое для дескрипторов файла канала в / из дочернего объекта. Тогда, когда вы используете select.select() для связи, у вас больше не будет этих блокировок. Однако вы должны использовать select () даже перед записью, вы можете получить EAGAIN ошибок при попытке чтения / записи, и в зависимости от логики вашего приложения у вас может возникнуть неопределенная ситуация ожидания в любом случае.

Я искренне рекомендую изучить структуру Twisted, в которой встроены функции дочерних процессов: http://twistedmatrix.com/documents/current/core/howto/process.html

...