我写了一个程序,它将~2600个文本文档解析成Python对象。 这些对象有很多对其他对象的引用,整体上它们描述了文档的结构。
使用pickle对这些对象进行序列化是没有问题的并且速度非常快。
在将这些文档解析为Python对象之后,我必须对它们进行一些繁重的计算,我想使它们并行。 我当前的解决方案将其中一个文档对象传递给一个工作函数,然后进行那些繁重的计算。
这些计算的结果被写入对象中,这些对象是文档对象中的属性。 然后,worker函数返回那些已更改的对象(仅返回那些属性对象,而不是原始文档对象)。
所有这些都适用于以下简化代码:
def worker(document_object):
# Doing calculations on information of document_object and altering objects which are attributes of document_object
return document_object.attribute_objects
def get_results(attribute_objects):
# Save results into memory of main process
# Parsing documents
document_objects = parse_documents_into_python_objects()
# Dividing objects into smaller pieces (8 and smaller worked for me)
for chunk in chunker(document_objects, 8):
pool = multiprocessing.Pool()
pool.map_async(worker, chunk, callback=get_results)
pool.close()
pool.join()
然而,有几个问题:
我知道每个document_object都必须被pickle并复制到一个worker进程中,而map_async()会将所有这些数据保存在内存中,直到pool.join()发生。
我不明白为什么这会占用如此多的内存(高达~12GB)。 当我将一个document_object pickle到一个文件中时,该文件的最大值约为500KB。
编辑:我在Ubuntu 14.04和Debian Wheezy上使用Python 2.7.6。
编辑:当我打印出工作人员功能的开始和结束时,就像评论中建议的dano一样,我得到类似下面的东西,它看起来并不平行。每一端和开始之间也有约5秒钟。
start <Process(PoolWorker-161, started daemon)>
end <Process(PoolWorker-161, started daemon)>
(~5 seconds delay)
start <Process(PoolWorker-162, started daemon)>
end <Process(PoolWorker-162, started daemon)>
(~5 seconds delay)
start <Process(PoolWorker-163, started daemon)>
end <Process(PoolWorker-163, started daemon)>
(~5 seconds delay)
start <Process(PoolWorker-164, started daemon)>
end <Process(PoolWorker-164, started daemon)>
(~5 seconds delay)
start <Process(PoolWorker-165, started daemon)>
end <Process(PoolWorker-165, started daemon)>
首先,我在这里发布的代码的简化版本中找不到问题。
问题是我想使用实例方法作为我的工作函数。 这在Python中没有开箱即用的功能,因为实例方法无法被腌制。 然而,there是Steven Bethard的一种解决方法,它可以解决这个问题(以及我使用过的)。
此解决方法的问题是,它需要pickle包含worker方法的类的实例。 在我的例子中,该实例具有引用大型数据结构的属性。 因此,每次实例方法被腌制时,所有这些庞大的数据结构都会被复制,导致上述问题。