Skip to main content
 首页 » 编程设计

python之Python 中的可重入子进程

2025年05月04日10over140

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

有没有办法避免这种死锁,而不必到处创建和清理临时文件?

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

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

请您参考如下方法:

我认为您的分析不正确。

您说进程死锁是因为标准输入和标准输出正在被 PDF 创建者进程使用。但是,由于这是使用 subprocess 模块启动的,因此 PDF 创建者进程的标准输入和标准输出 fds 只是 FastCGI 进程的常规管道 fds。没有理由不能让多个正在进行的子流程“通信”调用同时进行。

但是,请注意“通信”是一个阻塞调用。当您进程中的一个线程正在运行通信时,该线程将无法执行任何其他操作,例如为图像提供 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()