python 2.7 Popen:`close_fds`做什么?

时间:2017-07-06 13:38:20

标签: python exec file-descriptor

我在Python(2.7)中有一个Web服务器,它使用Popen将一些工作委托给子进程:

url_arg = "http://localhost/index.html?someparam=somevalue"
call = ('phantomjs', 'some/phantom/script.js', url_arg)

imageB64data = tempfile.TemporaryFile()
errordata = tempfile.TemporaryFile()

p = Popen(call, stdout=imageB64data, stderr=errordata, stdin=PIPE)
p.communicate(input="")

我看到间歇性的问题,在发生了一些Popen之后(大约64个),进程耗尽了文件描述符并且无法运行 - 它变得完全没有响应并且所有线程似乎都是如果他们试图打开任何文件或套接字,则永远阻止。

(可能相关:phantomjs子进程将URL调用加载回生成它的服务器。)

基于this Python bug report,我认为我需要在服务器进程内的所有close_fds=True调用上设置Popen,以减少文件描述符的泄漏。但是,我不熟悉exec周围的机制和文件描述符的继承这么多的Popen文档,上面提到的错误报告中的注释对我来说还不清楚。

听起来它实际上会在执行子进程之前关闭我的进程中所有打开的文件描述符(包括活动请求套接字,日志文件句柄等)。这听起来肯定比泄漏套接字更好,但仍然会导致错误。

然而,在实践中,当我在Web请求期间使用close_fds=True时,它似乎工作正常,到目前为止,我无法构建一个实际关闭任何其他请求套接字,数据库请求等的场景

文档声明:

  

如果close_fds为true,则在执行子进程之前将关闭除0,1和2之外的所有文件描述符。

所以我的问题是:它是否安全"并且"纠正"在多线程Python Web服务器中将close_fds=True传递给Popen?或者,如果其他请求同时执行文件/套接字IO,我是否应该预期会产生副作用?

2 个答案:

答案 0 :(得分:2)

我尝试使用Python 3.2 / 3.3&{39} subprocess32的{​​{1}}后端进行以下测试:

subprocess

我在import tempfile import subprocess32 as subprocess fp = open('test.txt', 'w') fp.write("some stuff") echoed = tempfile.TemporaryFile() p = subprocess.Popen(("echo", "this", "stuff"), stdout=echoed, close_fds=True) p.wait() echoed.seek(0) fp.write("whatevs") fp.write(echoed.read()) fp.close() 中得到了some stuffwhatevsecho this stuff的预期结果。

因此test.txtclose的含义似乎意味着父进程中的打开文件(套接字等)在执行之后将无法使用儿童过程。

另外值得注意的是:close_fds在POSIX系统上默认为subprocess32,AFAICT。这对我来说意味着它没有听起来那么危险。

答案 1 :(得分:0)

我怀疑close_fds解决了文件描述符泄漏到子流程的问题。想象一下打开一个文件,然后使用subprocess运行一些任务。如果没有close_fds,文件描述符将被复制到子进程,因此即使父进程关闭了文件,由于子进程,文件仍保持打开状态。现在,假设我们要使用shutil.rmtree删除具有另一个线程中的文件的目录。在常规文件系统上,这应该不是问题。该目录已按预期删除。但是,当文件驻留在NFS上时,会发生以下情况:首先,Python将尝试删除该文件。由于文件仍在使用中,因此将其重命名为.nfsXXX,其中XXX是一个十六进制数字。接下来,Python将尝试删除该目录,但是由于.nfsXXX文件仍驻留在其中,因此该操作变得不可能。