【问题标题】:python mmap.error: Too many open files. What's wrong?python mmap.error:打开的文件太多。怎么了?
【发布时间】:2011-08-15 09:10:33
【问题描述】:

我正在使用 pupynere 接口 (linux) 读取一堆 netcdf 文件。以下代码导致 mmap 错误:

import numpy as np
import os, glob
from pupynere import NetCDFFile as nc
alts = []
vals = []
path='coll_mip'
filter='*.nc'
for infile in glob.glob(os.path.join(path, filter)):
        curData = nc(infile,'r')
        vals.append(curData.variables['O3.MIXING.RATIO'][:])
        alts.append(curData.variables['ALTITUDE'][:])
        curData.close()

错误:

$ python2.7 /mnt/grid/src/profile/contra.py
Traceback (most recent call last):
  File "/mnt/grid/src/profile/contra.py", line 15, in <module>
  File "/usr/lib/python2.7/site-packages/pupynere-1.0.13-py2.7.egg/pupynere.py", line 159, in __init__
  File "/usr/lib/python2.7/site-packages/pupynere-1.0.13-py2.7.egg/pupynere.py", line 386, in _read
  File "/usr/lib/python2.7/site-packages/pupynere-1.0.13-py2.7.egg/pupynere.py", line 446, in _read_var_array
mmap.error: [Errno 24] Too many open files

有趣的是,如果我评论其中一个 append 命令(任何一个都可以!)它有效!我究竟做错了什么?我正在关闭文件,对吧?这在某种程度上与 python 列表有关。我使用了另一种效率低下的方法before(总是复制每个元素)。

PS:ulimit -n 产生 1024,程序在文件号 498 处失败。

可能与,但解决方案对我不起作用:NumPy and memmap: [Errno 24] Too many open files

【问题讨论】:

  • Python(如 perl)有一个“调试模式”,你可以用它来“看看库内部发生了什么”?试试看。它可能会有所帮助。您是否还可以在循环中调试打印打开文件句柄的数量(不知何故-;)...我猜它每次迭代都会打开两个文件句柄,仅基于 498(略小于 1024 的一半,并且 Python 会自己打开一些文件(可能是 25 多个?)。
  • 感谢您的有用评论。 python2.7 -d 没有提供更多信息(我猜在 python 的编译过程中没有启用调试)。跟踪打开文件的数量确实很有趣。我是怎么做到的?
  • 查看 Sehe 的“答案”...他告诉我们如何在 linux 上跟踪打开的文件句柄 ;-)

标签: python linux numpy mmap netcdf


【解决方案1】:

我的猜测是 pupynere 中的 mmap.mmap 调用使文件描述符保持打开状态(或创建一个新的)。如果你这样做会怎样:

vals.append(curData.variables['O3.MIXING.RATIO'][:].copy())
alts.append(curData.variables['ALTITUDE'][:].copy())

【讨论】:

  • 就是这样!使用 python 列表进行的优化阻止了文件的关闭。非常感谢。
  • 不错的一个。在 Python 中处理多内存映射文件有点麻烦,不是吗?!?!?真的应该记录在案,恕我直言。
  • 与其说是内存映射,不如说是切片默认返回视图。您可以通过重复创建一个大型 NxN 数组并从中切出一行以存储在列表中,重复 K 次来获得类似的行为。尽管您可能认为您只使用了 KxN 内存,但它实际上是 KxNxN,因为原始数组在有“视图”时无法回收。
  • 为什么[:]copy 方法是必需的?我以为[:] 暗示了一个副本?
【解决方案2】:

@corlettk:是的,因为它是 linux,所以strace -e trace=file 就可以了

strace -e trace=file,desc,munmap python2.7 /mnt/grid/src/profile/contra.py

这将准确显示打开的文件 - 甚至是文件描述符。

你也可以使用

ulimit -a

查看当前有效的限制

编辑

gdb --args python2.7 /mnt/grid/src/profile/contra.py
(gdb) break dup
(gdb) run

如果这导致在与映射文件相关的断点之前有太多断点,您可能希望在没有断点的情况下运行一段时间,手动中断 (Ctrl+C) 并在“正常”操作期间设置断点;也就是说,如果你有足够的时间:)

一旦中断,检查调用堆栈

(gdb) bt

【讨论】:

  • 我跑了strace,但我无法理解输出。有大量 python open() 命令(没有关闭),然后我的 netcdf 文件被打开,例如open("coll_mip/MIP.nc", O_RDONLY|O_LARGEFILE) = 3 然后是回溯。见here
  • 好吧,令人惊讶的是文件似乎永远不会关闭,但是打开的调用每次都会返回 3 (filedescriptor)。我不熟悉这种情况,但我怀疑内存映射代码中的某些内容由于某种原因会保留所有内存映射文件
  • 是的...一定是这样...出于某种深不可测的原因,即使我们告诉它关闭吸盘,NetCDFFile 仍然缓存文件(并且句柄打开)...有些一种“性能优化”,以节省时间在一个紧密的循环中不断重新打开文件,如果在给定的时间范围内没有“重新打开”它实际上会关闭文件(我自己使用过这个技巧,叹息).. .python中有“睡眠”吗?我充其量是一个蟒蛇菜鸟。如果是这样,请尝试暂停 5 秒,例如第 100 次迭代……看看 strace 中会发生什么。
  • @Sebastian,-e trace=file,desc,munmap 输出怎么样?这将获得基于文件描述符的系统调用(close()mmap() :) 以及当映射再次被拆除时。
  • @Seb,这是因为-e trace=file 显示了将文件 names 作为参数的系统调用; close(2) 将文件 descriptor 作为参数。有点烦人 :) 这是我几乎从不使用trace 功能的原因之一;查看 all 系统调用通常更有指导意义,grep -v 可以删除我不想在事后看到的那些。但是远程调试,过滤一下似乎还算公平。 :)
【解决方案3】:

嗯...也许,只是也许,with curData 可能会解决它?只是一个WILD的猜测。


编辑: curDataFlush 方法吗?你有没有试过在Close之前打电话?


编辑 2: Python 2.5 的 with 语句(直接来自 Understanding Python's "with" statement

with open("x.txt") as f:
    data = f.read()
    do something with data

...基本上它总是关闭资源(很像 C# 的 using 构造)。

【讨论】:

  • 是的,有一个flush() 方法。我不知道这在读取文件时会有用(我认为只是为了写作)。在curData.close() 之前调用curData.flush() 不会清除错误。我不熟悉with 的用法。你能指定吗?
  • @Seb... 见我上面的编辑... 无法在 SOF cmets 中格式化代码。
【解决方案4】:

nc() 电话的费用是多少?如果在每个文件上运行两次“足够便宜”,这行得通吗?

for infile in glob.glob(os.path.join(path, filter)):
        curData = nc(infile,'r')
        vals.append(curData.variables['O3.MIXING.RATIO'][:])
        curData.close()
        curData = nc(infile,'r')
        alts.append(curData.variables['ALTITUDE'][:])
        curData.close()

【讨论】:

  • 良好的调用,但产生相同的错误(现在在文件 496,而不是 498):-(
猜你喜欢
  • 1970-01-01
  • 2011-05-22
  • 2017-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 2016-04-21
相关资源
最近更新 更多