Повторно вводить подпроцессы в Python? - PullRequest
2 голосов
/ 15 декабря 2011

У меня есть модуль Python, который выполняет некоторую обработку с помощью модуля subprocess. Модуль считывает и записывает данные методом subprocess.communicate, используя каналы через stdin и stdout. Один из подпроцессов повторно входит в модуль Python и порождает еще один подпроцесс. Это блокирует приложение, потому что дескрипторы файлов stdin и stdout используются родительским подпроцессом.

Есть ли способ избежать этой тупиковой ситуации без необходимости везде создавать и очищать временные файлы?

Вот мой сценарий более подробно: это веб-приложение, работающее на сервере FastCGI. Когда делается запрос на файл PDF, создается подпроцесс для запуска стороннего приложения (wkhtmltopdf) для создания PDF. Затем это приложение начинает загружать изображения через мой модуль FastCGI - в том же процессе , что и в родительском процессе создателя PDF. Извлечение изображения вызывает другое стороннее приложение через subprocess, которое заходит в тупик, потому что stdin и stdout уже используются подпроцессом создателя PDF.

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

1 Ответ

0 голосов
/ 20 января 2012

Я не думаю, что ваш анализ верен.

Вы говорите, что процесс заходит в тупик, потому что stdin и stdout используются процессом создателя PDF. Однако, поскольку это было начато с использованием модуля подпроцесса, fds, которые являются stdin и stdout для PDF-creator-process, являются просто обычными конвейерными fds для FastCGI-процесса. Нет никаких причин, по которым вы не могли бы одновременно выполнять несколько текущих вызовов «связи» подпроцесса.

Однако учтите, что «общаться» - это блокирующий вызов. Пока один поток в вашем процессе выполняет comnunicate, этот поток больше не сможет ничего делать, например, обслуживать запросы HTTP для изображений.

В этом случае одно из решений - сделать ваш сервер многопоточным. Я удивлен, что это не так, поскольку большинство веб-серверов могут одновременно обслуживать несколько запросов (в разных потоках), поэтому это должно «просто работать».

Но, возможно, вы делаете что-то не так в том, как вы используете "общаться". Я написал небольшой пример того, как использовать несколько текущих вызовов «общаться» одновременно в одном и том же процессе, возможно, вы можете использовать его в качестве основы для решения. Не зная больше о вашей проблеме, трудно быть лучше.

import subprocess
from threading import Thread


sp1 = subprocess.Popen(["bash","-c","sleep 2;echo output1"],
                   stdin=subprocess.PIPE,
                   stdout=subprocess.PIPE,shell=False,close_fds=True)

sp2 = subprocess.Popen(["bash","-c","sleep 1;echo output2"],
                   stdin=subprocess.PIPE,
                   stdout=subprocess.PIPE,shell=False,close_fds=True)

def readfrom(which,sp):
    print "Thread #%d starting."%(which,)
    (stdout, stderr) = sp.communicate()
    print "Thread #%d finished, output: %s"%(which,stdout)

t1=Thread(target=readfrom,args=(1,sp1))
t2=Thread(target=readfrom,args=(2,sp2))
t1.start()
t2.start()
t1.join()
t2.join()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...