IOError: [Errno 24] 打开的文件太多:

58

我有一个非常大的文件,需要写入大约450个文件中。但是我遇到了错误,提示打开的文件太多。我在网上搜索了一些解决方法,但是没有帮助。

import resource
resource.setrlimit(resource.RLIMIT_NOFILE, (1000,-1))
>>> len(pureResponseNames) #Filenames 
434
>>> resource.getrlimit(resource.RLIMIT_NOFILE)
(1000, 9223372036854775807)
>>> output_files = [open(os.path.join(outpathDirTest, fname) + ".txt", "w") for fname in pureResponseNames]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 24] Too many open files: 'icd9_737.txt'
>>> 

我也从命令行更改了ulimit,如下所示:

$ ulimit -n 1200
$ 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) 1200
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
$ 

我仍然收到相同的错误。 PS:我也重新启动了系统并运行了程序,但没有成功。


2
这是一堆垃圾文件。你真的需要同时打开它们吗? - user2357112
3
我强烈建议您开发某种队列系统,这样所有这些文件句柄就不会保持打开状态,这非常低效。 - user1786283
由于输入文件非常大,我只想读取一次。另外,如果Python支持打开多个文件,为什么不使用它呢?只要打开的文件数少于256个,它就可以极大地简化我的生活。 - learner
1
奇怪。我刚刚尝试运行了你的代码,它对我来说可以工作(最多1000个文件)。 - ron rothman
你需要一个更好的算法。你真的不需要打开那么多文件来完成这个任务。 - Keith
@enginefree 在这种特定情况下打开这么多文件句柄可能是错误的,但在一般情况下,你所提到的“高低效率”是什么?如果一个进程同时打开了数千个文件句柄,会有任何变慢的情况吗? - josch
8个回答

28

你应该尝试使用 $ ulimit -n 50000 而不是 1200


/usr/bin/ulimit: 第4行: ulimit: 打开文件: 无法修改限制: 无效参数 显然,50000是无效的,但是1200可以工作。 - luckydonald
成功访问了一个被分割成1026个文件的vmdk!另外,如果你正在测试并将数量从50000降低到1000,然后再试图提高它,它是行不通的,我不得不关闭终端并在新的终端上运行才可以 :) - Aquarius Power
只需要添加对@dave4jr的类似问题的这个答案的引用:请注意,设置ulimit仅限于当前终端,并且一旦运行新会话,它将被删除。要在任务(例如)上使用此技巧,您需要修改limits.conf。 - tgrandje

27
“太多打开的文件”错误总是棘手的问题 - 你不仅需要调整 ulimit,还要检查系统范围内的限制和特定于OSX的设置。这个Stack Overflow帖子提供了有关OSX中打开文件的更多信息。(剧透警告:默认值为256)。
然而,通常很容易限制必须同时打开的文件数量。如果我们看一下Stefan Bollman的例子,我们可以轻松地将其更改为:
pureResponseNames = ['f'+str(i) for i in range(434)]
outpathDirTest="testCase/"
output_files = [os.path.join(outpathDirTest, fname) + ".txt" for fname in pureResponseNames]

for filename in range(output_files):
    with open(filename, 'w') as f:
        f.write('This is a test of file nr.'+str(i))

16

我将我的ulimit从1024改为4096,然后它就起作用了。以下是操作步骤:

使用以下命令检查您的描述符限制数量:

ulimit -n

对我来说,它是1024,我把它更新到4096,然后它就可以工作了。

ulimit -n 4096

10

如果由于某些原因(例如您正在使用第三方模块),无法关闭文件,则可以考虑基于hard最大限制而不是预定义的硬编码限制进行设置(如果您尝试设置hard+1,它将抛出ValueError):

import resource
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard))

我想要明确的是,即使在python进程仍在运行时您手动删除了创建的文件,它后面仍然会抛出类似的错误。


2

sudo vim /etc/security/limits.conf

添加

*         hard    nofile      500000
*         soft    nofile      500000

写入文件。


1
我强烈不建议您增加ulimit
例如,您的数据库可能会增长很多,导致生成比以前多得多的文件,这样就会超过您设定的限制,并认为这已足够。
这是一项耗时且容易出错的维护任务,因为您必须确保每个环境/服务器都正确设置了该限制,并且从未更改。
您应该确保将openclose结合使用,或者使用with语句(这更符合Python风格)。
第三方库可能会给您带来问题(例如,pyPDF2 PdfFileMerger.append在调用write方法之前会一直保持文件打开状态)。 我跟踪此问题的方式非常丑陋,但是在监视打开文件数的同时,在服务器上尝试几件事情就解决了(我的本地开发计算机运行在Mac OS X下,服务器是CentOs)。
watch 'lsof | grep "something-created-filenames-have-in-common" | wc -l'

对于 macOS 系统:brew install watch - luckydonald
ulimit通常会针对多个不同的数据库进行增加。 - Jeff West

0

如果提供的解决方案没有帮助,首先尝试重新启动计算机(而不是终端),然后再尝试这些解决方案。对我来说,这已经足够了:

ulimit -n 102400

-2
一个最小化的工作示例会很好。我使用以下脚本在Python 3.3.2,GCC 4.2.1和mac 10.6.8上得到了与ron.rothman相同的结果。你使用它时有错误吗?
    import os, sys
    import resource
    resource.setrlimit(resource.RLIMIT_NOFILE, (1000,-1))
    pureResponseNames = ['f'+str(i) for i in range(434)]
    try:
        os.mkdir("testCase")
    except:
        print('Maybe the folder is already there.')
    outpathDirTest="testCase/"
    output_files = [open(os.path.join(outpathDirTest, fname) + ".txt", "w") for fname in pureResponseNames]
    for i in range(len(output_files)):
        output_files[i].write('This is a test of file nr.'+str(i))
        output_files[i].close()

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