Python中可重入的子进程?

时间:2011-12-15 00:39:43

标签: python subprocess

我有一个Python模块可以用subprocess模块卸载一些处理。该模块使用subprocess.communicatestdin上的管道通过stdout方法读取和写入数据。其中一个子进程重新进入Python模块并生成另一个子进程。这会使应用程序死锁,因为父子进程正在使用stdinstdout文件描述符。

有没有办法避免这种死锁而无需在任何地方创建和清理临时文件?

这是我的场景更详细:它是在FastCGI服务器内运行的Web应用程序。当发出PDF文件请求时,会生成子进程以启动第三方应用程序(wkhtmltopdf)来创建PDF。然后,该应用程序开始通过我的FastCGI模块下载图像 - 与相同的过程作为PDF创建者的父进程。检索图像会通过subprocess调用另一个第三方应用程序,这会导致死锁,因为stdinstdout已被PDF创建器子流程使用。

this blog post(最后)提到了这个问题,但没有提供后续解决方案。我可能不得不求助于临时文件,但我更喜欢管道。有没有人遇到过这个问题?

1 个答案:

答案 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()