Как отправить большие объемы данных из разветвленного процесса? - PullRequest
3 голосов
/ 16 апреля 2009

У меня есть оболочка ctypes для библиотеки. К сожалению, эта библиотека не на 100% надежна (случайные ошибки и т. Д.). Из-за того, как он используется, я хочу, чтобы оболочка была достаточно устойчивой к сбоям библиотеки.

Лучшим способом сделать это, кажется, является разветвление процесса и отправка результатов от ребенка. Я хотел бы сделать что-то вроде этого:

r, w = os.pipe()
pid = os.fork()

if pid == 0:
    # child
    result = ctypes_fn()
    os.write(w, pickle.dumps(result))
    os.close(w)
else:
    # parent
    os.waitpid(pid, 0)
    result = os.read(r, 524288) # can be this big
    os.close(r)

    return pickle.loads(result)

Это не совсем работает, хотя. Разветвленный процесс зависает при записи. Я пытаюсь отправить слишком много сразу? Есть ли более простое решение этой проблемы?

Ответы [ 3 ]

4 голосов
/ 16 апреля 2009

Возможно, вы пытаетесь записать больше данных, чем может поместиться в канал, поэтому он блокируется, пока кто-то не придет и не прочитает часть этой информации оттуда. Этого никогда не произойдет, потому что единственным читателем является родительский процесс, который, по-видимому, вы написали, чтобы дождаться завершения дочернего процесса, прежде чем он что-либо читает. Это то, что мы называем тупик .

Вы можете рассмотреть возможность вызова os.waitpid и посмотреть, что получится. Другой вариант - посмотреть, есть ли в os.pipe какие-либо методы, дающие ему больший буфер (я не знаю, в какой среде я могу сказать).

2 голосов
/ 16 апреля 2009

Основная проблема заключается в том, что для канала существует ограничение в 64 КБ. Несколько возможных решений, от простых до сложных:

  1. Отправить меньше данных. zlib.compress может помочь в достижении лимита.
  2. Сохранять фактические данные в другом месте (файл, mmap, memcache), используя канал только для отправки управляющей информации.
  3. Продолжайте использовать трубу, но разбейте результат на части. Используйте два набора каналов, чтобы процессы могли общаться друг с другом и синхронизировать свое взаимодействие. Код более сложный, но в остальном он очень эффективен.
0 голосов
/ 16 апреля 2009

Одним из решений тупика, о котором упоминал ted.dennison, является следующий псевдокод:

#parent
while waitpid(pid, WNOHANG) == (0, 0):
    result = os.read(r, 1024)
    #sleep for a short time
#at this point the child process has ended 
#and you need the last bit of data from the pipe
result = os.read(r, 1024)
os.close(r)

Waitpid с параметром WNOHANG заставляет waitpid немедленно возвращаться, когда дочерний процесс еще не завершился. В этом случае он возвращает (0,0). Вы должны быть уверены, что не будете перезаписывать переменную результата каждый раз в цикле, как это делает приведенный выше код.

...