Python 中具有大尺寸数组的类的内存使用情况

问题描述 投票:0回答:1

我有课:

import numpy as np
from multiprocessing import Pool

class example
    def __init__(self):
        self.arr = np.random.rand(1000, 1000, 1000, 1000)

    def f(self, a):
        return self.arr[0, 1, 2, 3] * a

s = example()

if __name__ == "__main__":

    with Pool(8) as po:
        x = po.map(s.f, range(100))

因为我的

arr
中有一个巨大的 numpy 数组
class example
。我有一个称为
arr
的方法来进行一些计算。然后我初始化该类并调用该方法
f
100 次。在这种情况下,

  1. 我的程序的内存使用量主要是大
    arr
    加上一些小但可以忽略不计的
  2. 或者,它是 arr 内存大小的 100 倍,再加上我调用
    s.f
    100 次之后的一些小问题?

我在高性能计算设施中运行了类似的问题,但发现内存使用量比

arr
大得多。不知道为什么。

我坚信1是正确的。但最终结果更喜欢2?

python class oop memory numpy-ndarray
1个回答
0
投票

保存其他可能会改变程序运行方式的框架(例如,将检测您的代码的第 3 方日志库),此代码的行为如下:

对于多处理池中的每个进程,它将创建其所有数据。因此,如果池为“8”且映射如下,则需要 8 倍的

self.arr
大小 - 如果您不在代码中创建新的
example
类实例:池中的每个进程都会有一个
 example
实例。除此之外,每次您调用
f
时,它都会计算一个新数组,其大小与计算中所需的大小相同。

但是,如果任何代码calls“f”以不跨调用“回收”的方式存储其结果,这些中间值将保留在程序中 - 在您的情况下,它们可能会在每个工作进程中累积在您创建的多处理池中。

由于 multiprocessing.map 代码将尽快运行任务,因此当您从

x
获取一个结果时,当您在主代码中处理它时,后台进程将生成新项目并将其放入排队以便他们准备好。换句话说:根据处理
x
的每一项所需的时间(并且 100% 确定是否将
x
转换为
list
),是的,您可能会获得 100 个
f
输出的副本,在瞬态时刻,甚至更多:当使用多处理时,来回传递数据会产生开销 - 人们可能会说数据的原始副本、“传输中”副本和目标副本将存在:所以一次将存在
self.f
返回值的三倍。 (但是你不会得到
f
返回值的“300”倍。

可以更改代码,以便在完成上一次迭代的值后,只需向多处理工作线程提交新任务,而不是使用 Poll.map。您应该更改代码以直接使用

concurrent.futures.ProcessPoolExecutor
而不是
multiprocessing.Poll
,并在完成
submit
调用的先前结果后调用
example.f
进行下一次迭代
example.f
https://docs.python.org/3/library/concurrent.futures.html

© www.soinside.com 2019 - 2024. All rights reserved.