Python中打开的文件过多

24

我编写了一个测试套件,它需要频繁地对文件进行操作。在运行一段时间后(2小时),我遇到了IOError: [Errno 24] Too many open files: '/tmp/tmpxsqYPm' 的错误。我已经仔细检查了所有的文件句柄,确保它们都被正确关闭了,但这个错误还是存在。

我尝试使用resource.RLIMIT_NOFILE来获取允许的最大文件描述符数量以及当前打开的文件描述符数量:

def get_open_fds():

    fds = []
    for fd in range(3,resource.RLIMIT_NOFILE):
            try:
                    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
            except IOError:
                    continue

            fds.append(fd)

    return fds

所以,如果我运行以下测试:

print get_open_fds()
for i in range(0,100):
    f = open("/tmp/test_%i" % i, "w")
    f.write("test")
    print get_open_fds()

我得到了这个输出:

[]
/tmp/test_0
[3]
/tmp/test_1
[4]
/tmp/test_2
[3]
/tmp/test_3
[4]
/tmp/test_4
[3]
/tmp/test_5
[4] ...

很奇怪,我预期打开文件描述符的数量会增加。我的脚本是否正确?

我正在使用Python的日志记录器和子进程。这可能是导致文件描述符泄漏的原因吗?

谢谢, Daniel


请执行以下代码:cat /proc/sys/fs/file-max 和 cat /proc/sys/fs/file-nr - Paulo Scardine
2
你应该使用 resource.getrlimit(resource.RLIMIT_NOFILE)resource.RLIMIT_NOFILE 只是一个访问信息的常量。 - chuck
subprocess.Popen会导致类似的问题吗? - Joe
似乎相关:https://dev59.com/q3I-5IYBdhLWcg3wFkKO - dasWesen
3个回答

14

更正后的代码为:

import resource
import fcntl
import os

def get_open_fds():
    fds = []
    soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
    for fd in range(0, soft):
        try:
            flags = fcntl.fcntl(fd, fcntl.F_GETFD)
        except IOError:
            continue
        fds.append(fd)
    return fds

def get_file_names_from_file_number(fds):
    names = []
    for fd in fds:
        names.append(os.readlink('/proc/self/fd/%d' % fd))
    return names

fds = get_open_fds()
print get_file_names_from_file_number(fds)

4
最好说明原文有哪些问题,不是每个人都想玩“找不同”的游戏。 - Ian Goldby

14

你的测试脚本在每次迭代时都会覆盖 f,这意味着文件将会被每次关闭。记录到文件和使用管道的 subprocess 都会使用描述符,这可能会导致描述符耗尽。


我的错,谢谢提示!看起来get_open_fds()完成了它的工作。但是,resource.RLIMIT_NOFILE = 7,而我的错误是在打开1024个文件之后发生的。无论如何,我知道如何调试我的脚本 - 到目前为止谢谢! - dmorlock
1
@Informant,您能发布修复方法吗?我也遇到了同样的问题,但不知道如何解决。谢谢。 - AliBZ

10

resource.RLIMIT_NOFILE 确实是7,但这只是 resource.getrlimit() 的索引,而不是限制值本身... 你需要使用 resource.getrlimit(resource.RLIMIT_NOFILE) 来得到你想要的最大值来进行 range() 操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接