1

这是给你的 HDF5多处理专家...首先,我知道 python h5py 和多处理模块不一定彼此喜欢,但是我遇到了一个我无法弄清楚的错误。我正在处理的脚本创建一个临时的内存中hdf5 文件,将来自(pickle)输入文件的数据存储在内存文件中,然后一个多处理池对来自 temp 的数据执行(只读)操作HDF5 文件。

我已经能够隔离导致错误的代码,所以这里有一个简化的代码片段。当我在生成器函数中创建内存中的hdf5 文件,然后使用该生成器为多处理池生成参数时,我得到了一系列 HDF5 错误。这里有一些代码很简单,我可以让它重新创建错误:

import h5py
from multiprocessing import Pool
from itertools import imap

useMP = True

def doNothing(arg):
    print "Do nothing with %s"%arg

def myGenerator():
    print "Create hdf5 in-memory file..."
    hdfFile = h5py.File('test.hdf',driver='core',backing_store=False)
    print "Finished creating hdf5 in-memory file."
    yield 3.14159
    '''
    # uncommenting this section will result in yet another HDF5 error.
    print "Closing hdf5 in-memory file..."
    hdfFile.close()
    print "Finished closing hdf5 in-memory file."
    '''

if useMP:
    pool = Pool(1)
    mapFunc = pool.imap
else:
    mapFunc = imap

data = [d for d in mapFunc(doNothing,myGenerator())]

当我使用 itertools.imap(设置“useMP=False”)时,我得到以下输出,如预期的那样:

Create hdf5 in-memory file...
Finished creating hdf5 in-memory file.
Do nothing with 0

但是当我使用 Pool.imap 时,即使池仅使用单个工作线程创建,我也会得到以下输出:

Create hdf5 in-memory file...
HDF5-DIAG: Error detected in HDF5 (1.8.9) thread 139951680009984:
  #000: ../../../src/H5F.c line 1538 in H5Fopen(): unable to open file
    major: File accessability
    minor: Unable to open file
  #001: ../../../src/H5F.c line 1227 in H5F_open(): unable to open file: time = Wed Feb 27 09:32:32 2013
, name = 'test.hdf', tent_flags = 1
    major: File accessability
    minor: Unable to open file
  #002: ../../../src/H5FD.c line 1101 in H5FD_open(): open failed
    major: Virtual File Layer
    minor: Unable to initialize object
  #003: ../../../src/H5FDcore.c line 464 in H5FD_core_open(): unable to open file
    major: File accessability
    minor: Unable to open file
Finished creating hdf5 in-memory file.
Do nothing with 0

奇怪的是,这个错误不会使程序崩溃。我正在编写的导致此错误的脚本实际上按我的预期工作 - 但它为它创建的每个内存文件提供了上述错误。使用 itertools.imap 时没有错误,读取现有 HDF5 文件时没有错误,只有多处理和内存中 HDF5 文件的组合。

h5py 版本 2.1.1

hdf5 版本 1.8.9

Python 版本 2.7.3

4

1 回答 1

2

在挖掘了一些 h5py 文件之后,我找到了一个部分答案,尽管仍然不完整。h5py.File 类在h5py/_hl/files.py中定义。在调用 make_fid() 的 File 对象创建期间发生错误:

def make_fid(name, mode, userblock_size, fapl):
    """ Get a new FileID by opening or creating a file.
    Also validates mode argument."""
    ...
    elif mode == 'a' or mode is None:
        try:
            fid = h5f.open(name, h5f.ACC_RDWR, fapl=fapl)
            try:
                existing_fcpl = fid.get_create_plist()
                if userblock_size is not None and existing_fcpl.get_userblock() != userblock_size:
                    raise ValueError("Requested userblock size (%d) does not match that of existing file (%d)" % (userblock_size, existing_fcpl.get_userblock()))
            except:
                fid.close()
                raise
        except IOError:
            fid = h5f.create(name, h5f.ACC_EXCL, fapl=fapl, fcpl=fcpl)

如果文件存在,则以读/写模式打开。如果它不存在(内存文件就是这种情况),则 h5f.open() 调用会引发异常。正是这个对 h5f.open 的调用触发了 H5Fopen() 错误消息。

仍然悬而未决的问题是为什么仅在使用多处理时才打印错误?首先,我假设创建 HDF5 文件的生成器函数被主线程调用。好吧,事实并非如此。多处理池实际上创建了一个新线程来处理 imap 和 imap_unordered 的任务,但不用于 map/map_async。将pool.imap替换为pool.map,从主线程调用生成器函数,不打印错误信息。那么为什么在单独的线程中创建 HDF5 文件会引发错误呢?

- - - - 更新 - - - - - -

显然,h5py 会自动在主线程中使 HDF5 错误消息静音,因为 h5py 会处理错误。但是,它还不会自动使子线程中的错误静音。解决办法:h5py._errors.silence_errors()。此函数禁用当前线程中的自动 HDF5 错误打印。见 h5py问题 206。此代码使 HDF5 错误静音:

import h5py
from multiprocessing import Pool
from itertools import imap
import threading

useMP = True

def doNothing(arg):
    print "Do nothing with %s"%arg

def myGenerator():
    h5py._errors.silence_errors()
    print "Create hdf5 in-memory file..."
    hdfFile = h5py.File('test.hdf',driver='core',backing_store=False)
    print "Finished creating hdf5 in-memory file."
    yield 3.14159

if useMP:
    pool = Pool(1)
    mapFunc = pool.map
else:
    mapFunc = imap

data = [d for d in mapFunc(doNothing,myGenerator())]
于 2013-02-28T18:52:36.427 回答