我写了一个程序,可以总结如下:
def loadHugeData():
#load it
return data
def processHugeData(data, res_queue):
for item in data:
#process it
res_queue.put(result)
res_queue.put("END")
def writeOutput(outFile, res_queue):
with open(outFile, 'w') as f
res=res_queue.get()
while res!='END':
f.write(res)
res=res_queue.get()
res_queue = multiprocessing.Queue()
if __name__ == '__main__':
data=loadHugeData()
p = multiprocessing.Process(target=writeOutput, args=(outFile, res_queue))
p.start()
processHugeData(data, res_queue)
p.join()
真正的代码(特别是writeOutput()
)要复杂得多。 writeOutput()
仅使用它作为参数的这些值(意味着它不引用data
)
基本上它将一个巨大的数据集加载到内存中并对其进行处理。输出的写入被委托给一个子进程(它实际写入多个文件,这需要花费很多时间)。 因此,每次处理一个数据项时,它都会通过res_queue发送到子进程,res_queue会根据需要将结果写入文件。
子流程无需以任何方式访问,读取或修改loadHugeData()
加载的数据。子流程只需要使用主进程通过res_queue
发送的内容。这引出了我的问题和疑问。
在我看来,子流程将它放在庞大数据集的副本上(当用top
检查内存使用情况时)。这是真的?如果是这样,我怎么能避免id(基本上使用双内存)?
我使用的是Python 2.6,程序在linux上运行。
答案 0 :(得分:19)
multiprocessing
模块实际上基于fork
系统调用,该调用创建了当前进程的副本。由于您在fork
之前加载了大量数据(或创建了multiprocessing.Process
),因此子进程会继承数据的副本。
但是,如果您运行的操作系统实现COW(写时复制),除非您在父进程或子进程中修改数据,否则实际上只有一个数据副本存储在物理内存中(两者都是父和子将共享相同的物理内存页,尽管在不同的虚拟地址空间中);即使这样,也只会为更改分配额外的内存(以pagesize
为增量)。
您可以在加载大量数据之前调用multiprocessing.Process
来避免这种情况。然后,当您在父级中加载数据时,额外的内存分配将不会反映在子进程中。