如何使用多处理在HDF5文件中写入?

时间:2017-11-05 17:44:01

标签: python multiprocessing pytables

所以在我的代码中我有这样的东西:

import tables
import bson

def proc():
    data = bson.decode_file_iter(open('file.bson'), 'rb'))
    atom = tables.Float64Atom()
    f = tables.open_file('t.hdf5', mode='w')
    array_c = f.create_earray(f.root, 'data', atom, (0, m))

    for c,d in enumerate(data):
        for e,p in enumerate(d['id']):
            x = some_array1bym()
            array_c.append(x)

     f.close()

这很好用,但我想用多处理来解决这个问题,因为我是新手,我不知道该怎么做,我找到了这样的东西:

def proc():
    NCORE = 6               
    data = bson.decode_file_iter(open('file.bson'), 'rb'))
    atom = tables.Float64Atom()
    f = tables.open_file('t.hdf5', mode='w')
    array_c = f.create_earray(f.root, 'data', atom, (0, m))

    def process(q, iolock):
        while True:
           d = q.get()
           if d is None:
               break
           for e, p in enumerate(d['id']):
               x = some_array1bym()
               array_c.append(x)

     q = mp.Queue(maxsize=NCORE)
     iolock = mp.Lock()
     pool = mp.Pool(NCORE, initializer=process, initarg=(q,iolock))

     for c,d in enumerate(data):
        q.put(d)

     for _ in range(NCORE):
         q.put(None)
     pool.close()
     pool.join()

     f.close()

然而,这给了我一个空文件。

有人可以帮忙吗?

谢谢!

2 个答案:

答案 0 :(得分:0)

您已经误解了multiprocessing.Pool的使用。初始化Pool时,它会启动N个工作进程。 initializer参数只是一个在每个工作进程启动时运行一次的函数。它不是后续流程执行的任务。然后,您可以使用Pool.mapPool.apply(或其异步补充)等方法将作业实际提交到池中进行处理。

答案 1 :(得分:0)

我认为问题可能与array_c变量有关。在Pool forks之后,每个工作人员将获得此变量的副本。这将导致a)array_c的这些副本中的每一个都将尝试写入hdf5文件,给出未定义的结果或b)只有主进程中的副本(空的)将写入文件调用f.close()时我不确定哪个,因为我不熟悉pytables的内部。

array_c相比,qiolock在所有工作人员和主要线程之间共享。 qmp.Queue个实例,iolockmp.Lock个实例,这些类专门设计为一次由多个进程使用。我不认为pytables类也是如此。

您应该使用mp.Lock实例来确保只有一个进程一次写入文件。我认为您需要做的是将process函数修改为以下内容:

def process(q, iolock):
    while True:
        d = q.get()
        if d is None:
            break
        for e, p in enumerate(d['id']):
            x = some_array1bym()
            # acquire lock to ensure only one process writes data at once
            iolock.acquire()
            # get new handle to hdf5 file in append mode
            f = tables.open_file('t.hdf5', mode='a')
            # get new handle to data set and append new data
            array_c = tables.EArray(f.root, 'data')
            array_c.append(x)
            # close file and release lock to allow another process to write
            f.close()
            iolock.release()