Python子进程:打开的文件太多

Python子进程:打开的文件太多,python,subprocess,Python,Subprocess,我正在使用subprocess调用另一个程序,并将其返回值保存到变量中。此过程在循环中重复,数千次后程序崩溃,出现以下错误: Traceback (most recent call last): File "./extract_pcgls.py", line 96, in <module> SelfE.append( CalSelfEnergy(i) ) File "./extract_pcgls.py", line 59, in CalSelfEnergy

我正在使用subprocess调用另一个程序,并将其返回值保存到变量中。此过程在循环中重复,数千次后程序崩溃,出现以下错误:

Traceback (most recent call last):
  File "./extract_pcgls.py", line 96, in <module>
    SelfE.append( CalSelfEnergy(i) )
  File "./extract_pcgls.py", line 59, in CalSelfEnergy
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
  File "/usr/lib/python3.2/subprocess.py", line 745, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.2/subprocess.py", line 1166, in _execute_child
    errpipe_read, errpipe_write = _create_pipe()
OSError: [Errno 24] Too many open files

您可以尝试提高操作系统的打开文件限制:


ulimit-n 2048

我想问题是因为我正在使用子进程处理打开的文件:

cmd = "enerCHARMM.pl -par param=x,xtop=topology_modified.rtf,xpar=lipid27_modified.par,nobuildall -out vdwaals {0}".format(cmtup[1])
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
此处cmd变量包含刚创建但未关闭的文件的名称。然后
subprocess.Popen
调用该文件上的系统命令。在多次执行此操作后,程序因该错误消息而崩溃

所以我从中得到的信息是

关闭已创建的文件,然后对其进行处理


在子进程中打开文件。这是阻塞呼叫

ss=subprocess.Popen(tempFileName,shell=True)
 ss.communicate()
在Mac OSX(El Capitan)中,请参阅当前配置:

#ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 256
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited
将“打开文件”的值设置为10K:

#ulimit -Sn 10000
验证结果:

#ulimit -a

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 10000
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited

Popen()
创建的子进程可以从父进程继承打开的文件描述符(有限资源)。在POSIX上使用(自Python 3.2以来的默认设置),以避免它。另外,.

正如其他人所指出的,提高/etc/security/limits.conf中的限制,而且文件描述符对我个人来说是个问题,所以我做了

sudo sysctl -w fs.file-max=100000 
并添加到/etc/sysctl.conf:

fs.file-max = 100000
重新加载:

sudo sysctl -p
另外,如果您想确保您的流程不受任何其他内容(我的是)的影响,请使用

为了了解进程的实际限制是什么,对我来说,运行python脚本的软件也应用了它的限制,这些限制覆盖了系统范围的设置


在解决了这个错误的特殊问题后,在这里发布这个答案,希望它能帮助别人。

可能您多次调用该命令。如果是这样,每次执行
stdout=subprocess.PIPE
。在每次调用之间,请尝试执行
p.stdout.close()

Communicate()关闭管道,这样就不成问题了。最后,Popen()只是管道用完时碰巧运行的命令。。。问题可能在代码中的其他地方,其他文件处于打开状态。我注意到“SelfE.append”。。。是否打开其他文件并将其保存在列表中?在运行python脚本之前是否尝试过执行
ulimit-Sn unlimited
?实际上,该命令不会将限制提高到
/etc/security/limits.conf
中设置的限制以上。要提高它,您需要在该文件中放置如下行
*soft nofile 4096
/
*hard nofile 4096
(用您自己的值替换
4096
)。昨天遇到此问题,我必须编辑
/etc/security/limits.conf
,并通过ubuntu中的
ulimit-n
提高限制,以克服这个错误。我认为至少在所有情况下,这是行不通的。我在一个有1024个打开文件限制(Ubuntu默认)的系统上生成了1200个睡眠衍生进程,即使使用close_fds=True,它也会崩溃。所以我认为还有更多。因为您在打开的进程中仍然有超过限制的文件,并且这仅在您假设问题存在于未打开文件描述符的已完成进程中时才起作用。@Sensei它确实起作用:在父进程中打开文件(确保FD是可继承的),然后使用
close\u fds=False
(这两个都是旧Python版本的默认设置,请参见链接)。看看你会多快出现错误。显然,在一般情况下,
close_fds
无法阻止错误:你甚至不需要生成新进程就可以得到它。但事实并非如此。我运行了一个简单的for循环,生成了足够多的子进程,以达到操作系统的限制。我使用close_fds=True进行了此操作。它没有任何影响。我可能是错误的但我的猜测很简单,这个解决方案只有在生成几个子进程并且从不清理描述符的情况下才有效。在这种情况下,这个参数是有意义的,但是如果你真的打算一次生成并运行那么多进程,我看不出它有效。@Sensei:我知道它有效,因为stdlib中有测试可以执行请使用此选项(即,我知道它不仅适用于我)。现在,您的代码可能无法按预期工作。在这种情况下,请创建一个最小但完整的代码示例,描述您预期的确切行为以及发生的情况,并将其作为一个单独的SO问题发布(提及OS,Python版本).我认为你们两人之间存在误解,我想唤醒师说的是,如果你产生(并且不终止)许多进程,它仍然会崩溃。而我认为你说的是,如果你产生许多子进程(在某一点上会终止)然后这个解决方案起作用了。我有一个例子,我刚刚运行了许多
asyncio.create_subprocess_exec
(其中大多数是按顺序进行的,最多10个是同时打开的),但我仍然有一个“bug”,当我看我的脚本打开了多少描述符时,这个数字远远高于10,远远高于10。我正在尝试你的想法。
ulimit-a
的输出与2019年的Oktober(El Capitan 10.11.6)略有不同,例如,-n现在是“文件描述符”而不是“打开的文件”
-n:file descriptor
。但是
ulimit-Sn 50000
解决了我的问题。谢谢。为什么不
ulimit-Sn unlimited
sudo sysctl -p
cat /proc/{process id}/limits