使用h5py锁定HDF文件

5
我有一大堆代码,通过h5py与hdf文件交互。这些代码已经运行了多年。最近,在更改Python环境后,我收到了这个新的错误信息。
IOError:无法打开文件(无法锁定文件,errno = 11,错误消息=“资源暂时不可用”)
有趣的是,该错误在某些地方间歇性出现,在其他地方则持续存在。在它经常发生的地方,我查看了我的代码,并确认没有其他h5py实例连接到该文件,并且上一个连接已正确刷新和关闭。再次强调,这在环境变更之前都正常工作。
下面是我的conda环境片段:
h5py 2.8.0 py27h470a237_0 conda-forge hdf4 4.2.13 0 conda-forge hdf5 1.10.1 2 conda-forge

你能否构建一个最小化的示例,同时展示这个错误? - Tom de Geus
问题可能的来源:磁盘已满,共享文件系统,权限问题。正如@TomdeGeus所提到的,提供一个最小化的示例将有助于解决问题! - Pierre de Buyl
6个回答

2

根据我对这个问题的了解,它在一个不明显的方法中未能关闭文件。有趣的是,在某些情况下,解锁文件只需要重新启动Ipython,而其他情况则需要完全重新启动。


2

我有其他正在运行的进程,但我没有意识到。我是如何解决我的问题的:

  1. 使用 ps aux | grep myapp.py 查找正在运行 myapp.py 的进程编号。
  2. 使用 kill 命令终止该进程。
  3. 重新运行。

1
使用h5py.File(),同一个.h5文件可以被多次以只读模式("r")打开。但是h5py不支持多个线程。如果有多个并发读取器,则可能会出现糟糕的数据。

1
所有之前的答案都涉及到文件锁问题的方面,但没有一个完全解决根本原因和解决办法。本答案提供了导致问题的技术背景,总结了解决方案,并提供了避免将来出现问题的技巧。
首先,文件锁不仅仅是一个h5py的问题。它是在底层HDF5 API中实现的,适用于以写访问方式打开的任何文件。(这就是为什么基于Java的HDFView可能会引起文件访问冲突的原因。)如1个答案中所述,默认情况下,HDF5具有SWMR访问(单写;多读)。关于此的更多信息请参见末尾。每当一个文件以写访问方式打开时,API会“锁定”该文件,以防止其他进程的写访问。这样做是为了防止文件损坏。
因此,每当一个进程以写模式打开一个文件时,另一个进程就无法以写模式访问该文件。当发生这种情况时,您将在原始帖子中收到“无法锁定文件”的错误消息。(注意:这不会阻止另一个进程以只读模式打开文件。)
有几种情况可能会触发文件锁:
尝试同时运行两个具有写访问权限的进程访问同一个文件。有两个答案提到了这个问题: 同时运行另一个应用程序,例如myapp.py 以默认写访问模式运行HDFView。(与上述情况相同,其中HDFView是第一个应用程序。)
在上一个进程退出时,尝试以写模式打开文件,而没有正确关闭文件。 这通常发生在崩溃后。根据我的经验,这是最常见的原因。 如果程序在退出时没有正确关闭文件,也可能发生这种情况。(参见关于“以一种隐晦的方法未能关闭”的答案。)
如何避免文件锁定:
使用HDFView时,可以将默认访问模式设置为“只读”以避免问题。或者,可以使用文件菜单中的“打开为...只读”选项。
为了避免意外的文件锁定(崩溃或未关闭退出),需要对应用程序代码进行更改。在Python中,最好的方法是使用“with/as:”上下文管理器。通过上下文管理器,当程序正常退出或发生异常时,文件会自动关闭。
“with/as:”的示例:
with h5py.File('my_h5_file.hdf5','w') as h5f:
     some code that writes to your file
     end of that code block

如何重置文件锁定状态: 现在,如果所有尝试都失败了,你仍然无法以写模式访问文件,那么有一个HDF5实用程序可以解锁文件。(我认为你需要本地安装HDF5才能使用此实用程序。)命令行输入如下:
h5clear –-status filename.h5 (or just -s)

多进程写入访问:
如上所述,默认的HDF5行为是SWMR。然而,可以通过一些额外的工作实现并行写入访问。 h5py 使用 mpi4py 包来完成这个任务。然而,这需要一个HDF5并行构建,并且 h5py 必须以“MPI模式”编译。详细信息请参考h5py Parallel HDF5 docs


0

对我来说,我使用了multiprocessing来并行处理我的数据,并将文件句柄传递给多进程池。因此,即使我调用了close(),文件也不会关闭,直到由多进程池生成的所有子进程终止。

如果您正在使用多进程,请记得调用joinclose

        pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
        task_iter = pool.imap(...) # <- file is used in pool!
        ...
        pool.close()
        pool.join()

0

和其他答案类似,我已经打开了文件,但对我来说它是在一个单独的HDF5查看器中。


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