【问题标题】:Python multiprocessing memory usagePython多处理内存使用
【发布时间】:2013-01-22 21:08:03
【问题描述】:

我写了一个程序,可以总结如下:

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 发送到子进程,然后再根据需要将结果写入文件。

子进程不需要以任何方式访问、读取或修改loadHugeData()加载的数据。子进程只需要使用主进程通过res_queue发送的内容。这引出了我的问题和疑问。

在我看来,子进程拥有自己的庞大数据集副本(使用top 检查内存使用情况时)。这是真的?如果是这样,那么我怎样才能避免 id (本质上使用双内存)?

我使用的是 Python 2.6,程序在 linux 上运行。

【问题讨论】:

  • 你能重组你的代码以使用迭代器而不是加载所有的 loadHugeData 吗?如果它看起来像加载/处理/入队/出队/写入,您似乎可以这样做
  • 不幸的是,“hugeData”是一个制表符分隔的 txt 文件,基本上包含一个稀疏数组。我需要在处理过程中根据行号“随机访问”这些数据。因此将其加载到内存中(使用稀疏数组特定的优化)会使处理速度更快。
  • 建议使用 `beanstalkd 之类的东西来进行流程集成可能会过度设计,但如果知道它是否有帮助/扩展/执行会很有趣。像往常一样,别人的问题总是更有趣。

标签: python linux memory-management multiprocessing


【解决方案1】:

multiprocessing 模块有效地基于创建当前进程副本的fork 系统调用。由于您在fork(或创建multiprocessing.Process)之前加载了大量数据,因此子进程继承了数据的副本。

但是,如果您运行的操作系统实现了 COW(写时复制),那么物理内存中实际上只有一份数据副本,除非您在父进程或子进程中修改数据(两者父母和孩子将共享相同的物理内存页面,尽管在不同的虚拟地址空间中);即使这样,也只会为更改分配额外的内存(以pagesize 为增量)。

您可以通过在加载大量数据之前调用multiprocessing.Process 来避免这种情况。那么在父进程中加载​​数据时,额外的内存分配不会反映在子进程中。

编辑:在答案中反映@Janne Karila 的评论,因为它是如此相关:“还请注意,每个 Python 对象都包含一个引用计数,每当访问对象时都会修改该引用计数。因此,仅读取数据结构可能会导致 COW复制。”

【讨论】:

  • 做得比我快。 Linux是COW,因此父进程写入数据的那一刻,数据将被复制。如果父进程只读取数据,那么只有一个数据实例 BUT top(我几乎可以肯定)会将数据显示为属于两个进程。 meminfo 应该提供更准确的内存使用数字。
  • 确实如此。我认为现在最常见的操作系统是 COW(我只是想尽可能通用)。很棒的功能,但在解释基于进程的内存报告工具(即 top、ps 等)的输出时经常会引起混淆。 Linux 上的meminfo 将正确报告,Solaris 上的pmap 也一样;虽然不知道 Windows :)
  • 还要注意,每个 Python 对象都包含一个引用计数,每当访问该对象时都会修改该引用计数。所以,仅仅读取一个数据结构就会导致 COW 复制。
  • 回答问题。在加载数据之前调用multiprocessing.Process 似乎已经解决了这个问题。我也会调查meminfo
  • @isedev 即使评估表达式也涉及临时引用。
猜你喜欢
  • 1970-01-01
  • 2014-02-24
  • 2019-12-21
  • 2014-11-06
  • 1970-01-01
  • 1970-01-01
  • 2015-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多