我有一个Python模块可以用subprocess
模块卸载一些处理。该模块使用subprocess.communicate
和stdin
上的管道通过stdout
方法读取和写入数据。其中一个子进程重新进入Python模块并生成另一个子进程。这会使应用程序死锁,因为父子进程正在使用stdin
和stdout
文件描述符。
有没有办法避免这种死锁而无需在任何地方创建和清理临时文件?
这是我的场景更详细:它是在FastCGI服务器内运行的Web应用程序。当发出PDF文件请求时,会生成子进程以启动第三方应用程序(wkhtmltopdf)来创建PDF。然后,该应用程序开始通过我的FastCGI模块下载图像 - 与相同的过程作为PDF创建者的父进程。检索图像会通过subprocess
调用另一个第三方应用程序,这会导致死锁,因为stdin
和stdout
已被PDF创建器子流程使用。
this blog post(最后)提到了这个问题,但没有提供后续解决方案。我可能不得不求助于临时文件,但我更喜欢管道。有没有人遇到过这个问题?
答案 0 :(得分:0)
我不认为你的分析是正确的。
你说进程死锁是因为stdin和stdout正被PDF创建者进程使用。但是,由于这是使用子进程模块开始的,因此PDF-creator-process的stdin和stdout的fds只是FastCGI进程的常规管道fds。没有理由不能同时进行多个正在进行的子进程“通信”呼叫。
但请注意,“沟通”是一种阻止呼叫。当您的进程中的一个线程正在运行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()