【问题标题】:Multiprocessing with large array in state状态为大数组的多处理
【发布时间】:2026-01-28 21:25:02
【问题描述】:

我有一个在状态中存储大型numpy 数组的类。这导致multiprocessing.Pool 变得非常缓慢。这是一个 MRE:

from multiprocessing import Pool
import numpy
import time
from tqdm import tqdm

class MP(object):
    def __init__(self, mat):
        self.mat = mat

    def foo(self, x):
        time.sleep(1)
        return x*x + self.mat.shape[0]

    def bar(self, arr):
        results = []
        with Pool() as p:
            for x in tqdm(p.imap(self.foo, arr)):
                results.append(x)
        return results

if __name__ == '__main__':
    x = numpy.arange(8)
    mat = numpy.random.random((1,1))
    h = MP(mat)
    res = h.bar(x)
    print(res)

我在 CPU 上有 4 个内核,这意味着这段代码应该(并且确实)在大约 2 秒内运行。 (tqdm 将 2 秒显示为进度条,对于本示例来说,这并不是必需的)。但是,在主程序中,如果我执行mat = numpy.random.random((10000,10000)),则需要永远运行。我怀疑这是因为Pool 正在为每个工人制作mat 的副本,但我不确定这是如何工作的,因为mat 处于类的状态,并且不直接参与imap 调用.所以,我的问题是:

  1. 为什么会发生这种行为? (即Pool 在一个类中如何工作?它究竟腌制了什么?复制了哪些副本,以及通过引用传递了什么?)
  2. 有什么可行的解决方法来解决这个问题?

编辑:修改foo以使用mat,这更能代表我的实际问题。

【问题讨论】:

  • x 在你的主程序中有多大?
  • 在你的主程序中,你传递给p.imap的函数是否需要是MP的方法,还是可以是未绑定的函数?
  • @JeremyMcGibbon 好点。我想我的例子并不能很好地代表我的真正问题。所以,函数确实需要是MP的方法,因为函数实际上是从mat读取的。
  • 那么你的问题 2 没有答案,但希望我已经回答了问题 1。

标签: python numpy parallel-processing shared-memory python-multiprocessing


【解决方案1】:

如果你说mat 没有直接参与imap 调用,我猜MP 的状态一般不会在imap 调用中使用(如果是,请在下面评论和我会删除这个答案)。如果是这种情况,你应该把foo写成一个未绑定的函数而不是MP的一个方法。 mat 现在被复制的原因是因为foo 的每次执行都需要传入self,其中包含self.mat

无论垫子大小如何,以下内容都会快速执行:

from multiprocessing import Pool
import numpy
import time
from tqdm import tqdm


class MP(object):

    def __init__(self, mat):
        self.mat = mat

    def bar(self, arr):
        results = []
        with Pool() as p:
            for x in tqdm(p.imap(foo, arr)):
                results.append(x)
        return results

def foo(x):
    time.sleep(1)
    return x * x

if __name__ == '__main__':
    x = numpy.arange(8)
    mat = numpy.random.random((10000, 10000))
    h = MP(mat)
    res = h.bar(x)
    print(res)

如果foo确实需要通过MP,因为它确实需要从mat读取,那么没有办法避免向每个处理器发送mat,而你的问题2没有除了“你不能”之外的答案。但希望我已经回答了你的问题 1。

【讨论】: