【问题标题】:High memory usage for Pool in for loopfor循环中Pool的高内存使用
【发布时间】:2014-06-03 06:31:33
【问题描述】:

我有一个带有 2 个池的 for 循环:

if __name__ == '__main__':
    for length in range(1, 15, 5):

        def map_CCWP(it):
            return CCWP(G, length, Ep)
        pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
        Scores = pool.map(map_CCWP, range(R))

        S = []
        # some work to get S

        def map_AvgIAC (it):
            return avgIAC(G, S, Ep, I) 
        pool2 = multiprocessing.Pool(processes=multiprocessing.cpu_count())
        T = pool2.map(map_AvgIAC, range(4))

但是,在运行时,它会使用越来越多的内存,这可能是因为它每次都会创建新的池工作者。我尝试在每次迭代结束时删除池,但它仍然增加了内存量。

另一种选择是将池置于条件下:

if pool == None:
    pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())

而且它确实不使用那么多内存。但是,函数map_CCWPmap_AvgIAC 的每次迭代参数都会发生变化,而且我发现pool.map 将使用map_CCWP 和初始lengthmap_AvgIAC 和初始S

如何在每次迭代都会改变且不增加内存使用量的函数上运行 Pool?

【问题讨论】:

    标签: python multiprocessing pool


    【解决方案1】:

    默认情况下,池工作者在开始时创建并一直存在到结束。您没有初始化它们,因此在您的情况下保持它们的生命没有很大的性能优势。

    所以:

    pool = multiprocessing.Pool(processes=None, maxtasksperchild=1)
    

    将创建一个worker,运行进程,杀死它,然后创建一个新的worker。捕获的任何内存或资源都将被释放。如果你的记忆力增长不是太大,你可以增加每个孩子的任务数。

    请注意,我将进程定义为None。这与使用multiprocessing.cpu_count() 相同,但不那么冗长。

    在其他情况下,我遇到过有时(百万次或两次),随机孩子的内存会失控,机器会开始交换,一切都会卡住或非常慢。我的解决方法是:

    iterations = int(math.ceil(total / b_size))
    
    for block in xrange(iterations):
        restricted_iterator = iterator[block * b_size:(block + 1) * b_size]
        # This works because a slice can end beyond the length of the list.
    
        pool = multiprocessing.Pool(processes=None, maxtasksperchild=1)
        try:
            peaks = pool.map(caller, restricted_iterator)
        except Exception as e:
            raise e    # I don't expect this to ever happen.
        finally:
            pool.terminate()
                       # Kill the pool very dead.
        # Save the data to disk and free memory.
    

    我将工作分成几块,并逐一处理。这样一来,如果这个“疯狂的孩子”中有一个正在积累内存,其余的将在几分钟内完成,流浪的孩子将独自一人一段时间,有更多的可用内存。结果,它将在不到几分钟的时间内完成,因此程序的总延迟并没有那么大。通过调整b_size,我可以控制我清理的频率。 (在我的例子中,分成 10-20 个块,中间保存到磁盘,我仍然保持平均 CPU 使用率在 97% 左右,所以损失不多)。

    【讨论】:

    • 让我们讨论你答案的第一部分。我应该在没有我描述的任何条件的情况下使用pool = multiprocessing.Pool(processes=None, maxtasksperchild=1) 吗?我应该在每次迭代结束时以某种方式释放内存吗?现在我仍然观察到每次迭代后内存的增加。
    • 使用该行将确保不会留下任何 Python 对象使您的记忆变得混乱,这应该可以帮助您完成大部分工作。可以肯定的是,一旦完成,您还应该 terminate 池。可能是CCWP 有内存泄漏,您可以通过在没有池的情况下反复运行来检查它。问题也可能是输出本身很大,所以内存必须增长。我看不出使用条件会有什么帮助。
    • 关于CCWP泄漏。您的意思是只使用map 而不是pool.map?在这种情况下,我仍然增加了内存,虽然没有那么大。使用pool.map 我有 2.3Gb,没有我有 1.8Gb。关于产量大。每次迭代后,我只想知道T 这只是一个整数。其他一切都可以释放。在这种情况下,我还应该期望内存增加吗?
    • 因此,CCWP 由于多处理而泄漏了 500 MB,而其本身泄漏了 1.8 GB。先修复 CCWP,然后再担心 500 MB(除非 1.8 GB 是数据输出)。 T 不能是整数,正如您所展示的,它是一个包含四个元素的列表。当你停止使用它们时,你可以del 大对象,并且将每个迭代包装在一个函数中,最后会为你做这件事;类似:compute_T(length) for length in...
    • 等等.. 但在我开始运行一切之前我已经使用了 1.3Gb。在运行时,它可以达到整个内存使用量(~5Gb)。关于 T。你是对的:T 是一个列表,然后我对其进行规范并得到一个数字。在任何情况下,我在每次迭代中都使用map_CCWPScoresSpool,但它们对于所有迭代都是不同的。因此,一旦我使用它们,我就不需要它们了;但我覆盖了它们,并认为每次迭代都会使用相同数量的内存。不是这样吗?
    【解决方案2】:

    看起来您在程序生命周期内创建了越来越多的池。如果您在 for 循环之前初始化一个固定大小的池,然后您的 for 循环只将任务添加到该池中怎么办?这样,从概念上讲,您的并行进程受到池大小的限制,因此内存消耗应该得到控制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-31
      • 1970-01-01
      • 2015-03-11
      • 1970-01-01
      • 2022-11-05
      • 2021-10-28
      • 2018-01-30
      • 1970-01-01
      相关资源
      最近更新 更多