2011-12-15 4 views
2

subprocess 모듈을 사용하여 일부 처리를 오프로드하는 Python 모듈이 있습니다. 모듈은 stdinstdout 이상의 파이프를 사용하여 subprocess.communicate 메서드를 통해 데이터를 읽고 씁니다. 서브 프로세스 중 하나가 파이썬 모듈을 다시 입력하고 또 다른 서브 프로세스를 생성합니다. 부모 하위 프로세스에서 stdinstdout 파일 설명자가 사용 중이므로 응용 프로그램이 교착 상태가됩니다.Python에서 재진입하는 하위 프로세스?

어디서나 임시 파일을 만들고 정리할 필요없이이 교착 상태를 피할 수있는 방법이 있습니까?

내 시나리오는 다음과 같습니다. FastCGI 서버에서 실행되는 웹 응용 프로그램입니다. PDF 파일에 대한 요청이 있으면 하위 프로세스가 생성되어 타사 응용 프로그램 (wkhtmltopdf)을 시작하여 PDF를 작성합니다. 이 응용 프로그램은 내 FastCGI 모듈을 통해 이미지를 다운로드하기 시작합니다. 동일한 프로세스을 PDF 작성자의 부모 프로세스로 다운로드합니다. 이미지를 가져 오는 것은 subprocess을 통해 다른 타사 응용 프로그램을 호출합니다. 이는 stdinstdout이 PDF 작성자 하위 프로세스에서 이미 사용되고 있기 때문에 교착 상태에 빠집니다.

이 문제는 this blog post (끝 부분)에서 언급되었지만 후속 솔루션이 제공되지 않았습니다. 임시 파일을 사용해야 할 수도 있지만 파이프를 선호합니다. 누구든지 전에이 문제가 발생 했습니까?

+0

더 나은 IPC 메커니즘을 살펴 보는 것이 좋습니다. 제롬 큐 (zeromq)를 보길 원할지도 모르지만, rabbitmq와 같은 큰 메시지 서버에 의존하지 않고도 이런 일을 훨씬 쉽게 처리 할 수 ​​있습니다. http://zguide.zeromq.org/page:all –

+0

고맙습니다. #tom, 불행히도 FastCGI 서버는 공유 호스팅 서비스에서 실행됩니다. 하위 프로세스의 재진입 부분을 다림질하여 문제를 해결할 수 있었지만 여전히 일반적인 시나리오가 해결 가능한지 알고 싶습니다. – simonhaines

+0

hmmm 호스트가 어떤 제한을 가지고 있는지 알 수는 없지만 셀러리 http://celeryproject.org/는 프로세스를 사용할 수 있으므로 유용 할 수도 있습니다. 코드를보고 그들이 어떻게하는지보십시오. –

답변

0

귀하의 분석이 정확하다고 생각하지 않습니다.

stdin 및 stdout이 PDF 작성자 프로세스에서 사용 중이므로 프로세스가 교착 상태가된다고합니다. 그러나 하위 프로세스 모듈을 사용하여 시작되었으므로 PDF 작성자 프로세스의 표준 및 표준 출력 파일은 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() 
+0

답장을 보내 주셔서 감사합니다. 귀하의 솔루션은 문제의 재진입 부분을 해결하지 못하는 것 같습니다.sp1과 sp2가 동일한 프로세스에 다시 들어가서 새 sp1과 sp2를 시작하면 어떻게됩니까? 부모 프로세스가 교착 상태에 빠졌다고 믿습니다. – simonhaines

+0

동일한 프로세스를 다시 입력하는 것을 어떻게 의미합니까? subprocess.Popen에 의해 생성 된 서브 프로세스가 부모 프로세스를 직접 호출하는 방법은 없습니다. 파이프, 소켓 또는 유사한 것을 통해 서버 프로세스와 통신 할 수 있습니다. 물론 서버가 하위 프로세스가 완료되기를 기다리는 중 일 경우 데드락이 생기지 만 파이썬 하위 프로세스 모듈의 제한 사항과는 아무런 관련이 없습니다. 그리고 work-around는 쉽습니다 - subprocess를 실행하십시오. 위의 예제에서와 같이 자신의 스레드에서 호출을 호출합니다. –

+0

파이프에서 입력을 읽고 하위 프로세스를 호출하고 하위 프로세스의 출력을 동일한 파이프에 다시 쓰는 상위 프로세스를 생각해보십시오. 이제이 서브 프로세스가 부모의 입력 파이프에 쓰고 파이프에서 읽는 것을 기다리는 경우? 나는 결과가 교착 상태라고 믿는다. 그리고 이런 종류의 문제는 내가 가지고있는 문제를 모의 실험한다. 혼란스러운 용어에 대해 유감스럽게 생각합니다 (이것은 동일한 프로세스를 다시 입력해야한다는 의미입니다). 어쨌든,이 가능성을 단순히 피하기 위해 서브 프로세스를 재 설계 했으므로 요점은 중요하지 않습니다. 답장을 보내 주셔서 감사합니다. – simonhaines

관련 문제