Python子进程:打开文件太多

时间:2013-05-13 16:23:05

标签: python 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

非常感谢任何想法如何解决这个问题!

评论提供的代码:

cmd = "enerCHARMM.pl -parram=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)
out, err = p.communicate()

9 个答案:

答案 0 :(得分:23)

在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

答案 1 :(得分:12)

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

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调用该文件上的系统命令。多次执行此操作后,程序因该错误消息而崩溃。

所以我从中学到的信息是

  

关闭您创建的文件,然后进行处理

由于

答案 2 :(得分:5)

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

ulimit -n 2048

答案 3 :(得分:4)

Popen()创建的子进程可以从父进程继承打开的文件描述符(有限资源)。在POSIX上使用close_fds=True(默认自Python 3.2),以避免它。另外,"PEP 0446 -- Make newly created file descriptors non-inheritable" deals with some remaining issues (since Python 3.4)

答案 4 :(得分:3)

改用上下文管理器:

cmd = "enerCHARMM.pl -parram=x,xtop=topology_modified.rtf,xpar=lipid27_modified.par,nobuildall -out vdwaals {0}".format(cmtup[1])
with subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) as p:
    out, err = p.communicate()

这将在最后一行之后关闭 p.stdoutp.stderr

Python 相关代码:https://github.com/python/cpython/blob/208a7e957b812ad3b3733791845447677a704f3e/Lib/subprocess.py#L1031-L1038

相关文件:https://docs.python.org/3/library/subprocess.html#subprocess.Popen

答案 5 :(得分:2)

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

package lab4;
import java.util.Scanner;

public class Lab4 {

    public static void main(String[] args) {
    CriticalClasses course;
    course = new CriticalClasses("Ingegneria");
    System.out.println(course);

    CriticalClasses classes;
    classes = new CriticalClasses("number1", "number2","number3");
    //System.out.println(java.util.Arrays.toString(classes));
    //System.out.println(classes); these are comments because i dont know what to write
}

将fs.file-max = 100000的行添加到/etc/sysctl.conf(使用sysctl -p重新加载)

此外,如果您想确保您的流程不受其他任何事情的影响(我的是),请使用

sudo sysctl -w fs.file-max=100000 

找出你的进程的实际限制是什么,对我来说,运行python脚本的软件也有其限制,它已经覆盖了系统范围的设置。

在解决此错误的特定问题之后,在此处发布此答案,并希望它可以帮助某人。

答案 6 :(得分:1)

也许您多次调用该命令。如果是这样,则每次执行stdout=subprocess.PIPE时。在每次通话之间尝试进行p.stdout.close()

答案 7 :(得分:0)

在子进程中打开文件。这是阻止通话。

ss=subprocess.Popen(tempFileName,shell=True)
 ss.communicate()

答案 8 :(得分:0)

如果你在 Linux 上工作,你可以很容易地调试这个问题

1 - 启动最终会因终端中打开的文件太多而失败的命令。

python -m module.script

2 - 让它运行一段时间(以便它可以开始打开实际文件),只要您认为它已经完成,只需按 CTRL+Z 即可暂停该进程。您将获得带有进程 ID 的输出。

^Z
[2]  + 35245 suspended  python -m module.script

35245 是您的 PID。

3 - 现在您可以检查实际打开和未关闭的文件。

ls -alht /proc/35245/fd/

就我而言,我正在做与原始帖子非常相似的事情,但在添加一些数据并实际运行 tempfile.mkstemp() 之前,我使用 subprocess.Popen 创建了一个临时文件。

在这种情况下,您需要关闭文件两次,一次用于添加信息,第二次用于 mkstemp

fd, path = tempfile.mkstemp()
with open(path, "wb") as f:
    f.write(bytes('my data', encoding='utf8'))
    f.close()   # this is one time
process = subprocess.Popen("my command that requires the previous file" ,[...])
os.close(fd)   # this is second time and the one I missed