我有几个正在解析的大型xml文件(提取一些数据子集并写入文件),但是每个文件都有很多文件和大量记录,所以我尝试并行化。在
首先,我有一个生成器从文件中提取记录(这很好):def reader(files):
n=0
for fname in files:
chunk = ''
with gzip.open(fname, "r") as f:
for line in f:
line = line.strip()
if ''):
chunk += line
continue
if line == '':
chunk += line
n += 1
yield chunk
chunk = ''
一个过程函数(这里的细节与此无关,但也可以很好地工作):
^{pr2}$
当然,这种天真的、非并行的方法很简单:records = reader(files)
with open(output_filepath,'w') as fout:
for record in records:
result = process(record)
fout.write(result+'\n')
但现在我想把它并行化。我首先考虑使用一个简单的基于映射的方法,每个进程处理其中一个文件,但是文件的大小完全不同(有些文件非常大),所以我认为这是并行化的一个非常低效的使用。这是我目前的做法:
将多处理作为mp导入def feed(queue, records):
for rec in records:
queue.put(rec)
queue.put(None)
def calc(queueIn, queueOut):
while True:
rec = queueIn.get(block=True)
if rec is None:
queueOut.put('__DONE__')
break
result = process(rec)
queueOut.put(result)
def write(queue, file_handle):
records_logged = 0
while True:
result = queue.get()
if result == '__DONE__':
logger.info("{} --> ALL records logged ({})".format(file_handle.name,records_logged))
break
elif result is not None:
file_handle.write(result+'\n')
file_handle.flush()
records_logged +=1
if records_logged % 1000 == 0:
logger.info("{} --> {} records complete".format(file_handle.name,records_logged))
nThreads = N
records = reader(filelist)
workerQueue = mp.Queue()
writerQueue = mp.Queue()
feedProc = mp.Process(target = feed , args = (workerQueue, records))
calcProc = [mp.Process(target = calc, args = (workerQueue, writerQueue)) for i in range(nThreads)]
writProc = mp.Process(target = write, args = (writerQueue, handle))
feedProc.start()
for p in calcProc:
p.start()
writProc.start()
feedProc.join()
for p in calcProc:
p.join()
writProc.join()
feedProc.terminate()
writProc.terminate()
for p in calcProc:
p.terminate()
workerQueue.close()
writerQueue.close()
现在,这种方法的工作原理是所有的东西都被写入文件,但是当最后试图加入进程时,它就会挂起,我不知道为什么。所以,我的主要问题是,我在这里做错了什么,以致于我的工作进程没有正确地终止,或者发出它们已经结束的信号?在
我想我可以通过给join的调用添加超时来“简单”地解决这个问题,但这(a)在这里似乎是一个相当不雅观的解决方案,因为任务有明确的完成条件(即,一旦文件中的每个记录都被处理完,我们就完成了),并且(b)我担心这可能会带来一些问题(例如,如果我把超时设置得太短,它不能在所有事情都处理完之前终止它吗?当然,把它弄得太长只是在浪费时间。在
如果有人有想法,我也愿意考虑一种完全不同的并行方法(队列似乎是一个不错的选择,因为文件很大,只读取和生成原始记录需要时间)。在
额外问题:我知道这种方法决不能保证我写入文件的输出与原始数据的顺序相同。这不是一个大问题(对减少的/处理过的数据进行排序不会太麻烦),但是保持顺序会很好。因此,如果有人能找到一个解决方案,确保能保持原有秩序,那就格外感谢。在