所以在我的代码中我有这样的东西:
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()
然而,这给了我一个空文件。
有人可以帮忙吗?
谢谢!
答案 0 :(得分:0)
您已经误解了multiprocessing.Pool
的使用。初始化Pool
时,它会启动N
个工作进程。 initializer
参数只是一个在每个工作进程启动时运行一次的函数。它不是后续流程执行的任务。然后,您可以使用Pool.map
或Pool.apply
(或其异步补充)等方法将作业实际提交到池中进行处理。
答案 1 :(得分:0)
我认为问题可能与array_c
变量有关。在Pool forks之后,每个工作人员将获得此变量的副本。这将导致a)array_c
的这些副本中的每一个都将尝试写入hdf5文件,给出未定义的结果或b)只有主进程中的副本(空的)将写入文件调用f.close()
时我不确定哪个,因为我不熟悉pytables
的内部。
与array_c
相比,q
和iolock
在所有工作人员和主要线程之间共享。 q
是mp.Queue
个实例,iolock
是mp.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()