1

これは、HDF5マルチプロセッシングの専門家向けです...まず第一に、python h5py とマルチプロセッシング モジュールが必ずしも互いに好きではないことを知っていますが、理解できないエラーが発生しています。私が取り組んでいるスクリプトは、一時的なインメモリhdf5 ファイルを作成し、(pickle) 入力ファイルからのデータをインメモリ ファイルに格納し、マルチプロセッシング プールが一時ファイルからのデータに対して (読み取り専用) 操作を実行します。 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 を使用すると、プールが 1 つのワーカー スレッドのみで作成された場合でも、次の出力が得られます。

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() の呼び出しでファイル オブジェクトを作成するときに発生します。

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() 呼び出しで例外が発生します。H5Fopen() エラー メッセージをトリガーしているのは、この h5f.open への呼び出しです。

まだ未解決の問題は、マルチプロセッシングを使用している場合にのみエラーが出力されるのはなぜですか? まず、HDF5 ファイルを作成するジェネレーター関数がメイン スレッドによって呼び出されていると想定していました。そうではありません。マルチプロセッシング プールは、実際には imap および imap_unordered のタスクを処理する新しいスレッドを作成しますが、map/map_async のタスクは作成しません。pool.imap を pool.map に置き換えると、ジェネレーター関数がメイン スレッドから呼び出され、エラー メッセージは出力されません。では、別のスレッドで HDF5 ファイルを作成すると、なぜエラーが発生するのでしょうか?

- - - - アップデート - - - - - -

どうやら、h5py が代わりにエラーを処理するため、h5py はメイン スレッドで HDF5 エラー メッセージを自動的に無音にします。ただし、子スレッドのエラーを自動的に黙らせることはまだありません。解決策: h5py._errors.silence_errors(). この関数は、現在のスレッドでの自動 HDF5 エラー出力を無効にします。h5py issue 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 に答える