【问题标题】:Why number of sub processes in python influence the memory consumption of the sub processes?为什么python中子进程的数量会影响子进程的内存消耗?
【发布时间】:2013-01-16 09:59:00
【问题描述】:

我在python中有一个非常有趣的案例。

主进程创建N个子进程。 子流程是继承自 multiprocessing.Process 的类。

现在,当子进程数为10个时,每个子进程消耗大约15M的驻留内存。 但是,当我将子进程数增加到100个时,每个子进程的驻留内存消耗都跃升到50M左右!!!

任何人都可以解释这种内存跳跃/建议如何避免它?

下面是子流程类的结构:

class MySubProcess(multiprocessing.Process):
    def __init__(self, sub_process_number):
        multiprocessing.Process.__init__(self, target=self.go)

        self.m_sub_process_number = sub_process_number


    def go(self):
        self.m_config = global_config
        while (True):
        ....

非常感谢!!!

【问题讨论】:

  • 您介意透露一下 python 风格/平台/版本吗?
  • 我使用的是python 2.7.3,linux 64bit
  • 你是说15M还是50M是子进程消耗的内存?如果是这样,为什么是如何启动子流程的问题?好像是子进程中运行的程序的问题,你不说。
  • 我无法理解的是为什么子进程数量的增加会导致所有子进程的内存消耗增加。虽然我所期望的是,内存增加是由于添加了新的子进程,而不是因为现在每个子进程都消耗更多的内存。

标签: python


【解决方案1】:

当我尝试一个简单的例子时,每个子进程除了 time.sleep() 什么都不做,我没有看到这种行为,所以我不相信这是 multiprocessing 模块固有的东西。

我最好的猜测是fork() 的内存复制功能,multiprocessing 很可能在后台使用。在 Unix 上 fork 一个新进程的语义要求将父进程的整个内存空间复制到子进程中。因此,假设您要在启动其中任何一个之前创建这些MySubProcess 结构的列表。然后,该列表将被复制到每个子进程的地址空间中,因此当您查看每个这些进程的常驻大小时,它会显得大得多(假设您的结构占用大量内存)。

此外,您在启动子进程之前分配的任何其他内存都将被复制,但实例列表是我能想到的主要内容,随着您分配更多进程,它的大小会增加。根据您的代码,可能还有其他数据结构会随着进程数量(例如工作队列)而扩展。

如果您 del 在每个孩子的上下文中不需要的所有内容,您可能会发现它们的大小会变小,但这取决于 Python 分配器和系统内存分配器,所以这绝不是肯定的。从本质上讲,Python 可能会保留释放的内存以供重用,即使 Python 解释器没有,系统分配器也可能会这样做。简而言之,这可能不值得付出努力 - 有关更多信息,请参阅我的答案末尾。

然而,这并没有看起来那么糟糕,因为 Linux(和其他现代 Unix 变体)使用所谓的copy-on-write 语义来确保fork() 的行为不会那么低效。从本质上讲,子进程保持对与父进程相同的内存页面的引用 - 只要两个进程都没有更改任何内容,内存不会实际上重复,尽管如果您将内存使用数据相加pstop 对于这两个进程,它将被计算两次,因为它们的每进程方法不够聪明,无法注意到页面的共享。这与拥有多个指向同一个基础文件的硬链接没有什么不同,如果您曾经遇到过这种情况的话。

一旦一个进程写入内存页面,它然后被复制(因此名称为“写时复制”),因此将使用实际的物理内存。在这种情况下,所需的额外内存量很难预测,因为它涉及将 Python 数据结构一直映射到物理内存页面。然而,原则本身才是重要的。

您可以使用free 实用程序来测试我的理论是否正确,以显示整体系统内存使用情况并比较两种情况之间的数据 - 如果我是对的,您会看到一些 在 100 个子进程的情况下增加了内存,但不如检查每个进程的内存使用所建议的那么多。不要忘记使用第二行中的数字(即-/+ buffers/cache 行),因为这将消除两次测试之间文件系统缓存中的任何更改。

假设这是正确的,最好的办法是在父进程分配大量内存之前尽早尝试启动子进程。然而,除了你在这方面的最大努力之外,你可能不需要太担心它 - 即使页面在写入时被复制,它们也不会被子进程访问,因此将被换出到磁盘需要并且可能永远不会换回,因此不会对性能造成太大影响(除非您的平台没有任何交换)。

最后一点 - 在实践中,创建更多的工作进程可能没有什么意义,而不是机器上的核心,通常不超过 8 个或 16 个左右,除非您使用的是极其专业的硬件。如果你创建了太多的进程,那么你可能浪费了更多的时间来调度它们而不是你获得的收益——无论你做什么,你都无法获得比物理内核更多的并行化(尽管hyperthreading 稍微复杂化了这一点)。

This other SO question 可能会提供一些更有用的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    相关资源
    最近更新 更多