【问题标题】:How can I make many perallel processes make changes to a single shared NumPy array?如何让多个并行进程更改单个共享 NumPy 数组?
【发布时间】:2015-07-28 21:56:06
【问题描述】:

我已经在互联网上搜寻了答案,但我找不到任何适用于我的情况。我读过multiprocessing.Manager,尝试来回传递东西,但似乎都不能很好地与NumPy数组一起使用。我尝试过使用Pool,但是我的目标方法没有返回任何东西,它只是进行了更改到一个数组,所以我也不知道如何设置它。

现在我有:

def Multiprocess(self, sigmaI, sigmaX):
    cpus = mp.cpu_count()
    print('Number of cpu\'s to process WM: %d' % cpus)

    processes = [mp.Process(target = self.CreateMatrixMp, args = (sigmaI, sigmaX, i,)) for i in range(self.numPixels)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()

目标函数CreateMatrixMp 获取传递的值,并在进行计算后将值附加到数组data。这个数组被声明为self.data = numpy.zeros(self.size, numpy.float64)。如果CreateMatrixMp 方法的详细信息有帮助,我也可以发布。

我尝试在上面运行进程的地方添加这个:

mgr = mp.Manager()
sharedData = mgr.Array(ctypes.c_numpy.float64, self.data)

然后将sharedData传递给CreateMatrixMp,可以在其中进行修改。一旦所有进程都运行完毕并且数组完成后,我只需执行self.data = sharedData。

但这不起作用(尽管我知道我没有正确设置它)。这应该如何使用 NumPy 数组来完成?我希望每个进程(将有数千个)附加到同一个数组。

非常感谢任何帮助。

【问题讨论】:

  • 你能详细说明为什么这个问题需要数千个进程吗?您可能会在此之前达到收益递减点,请参阅stackoverflow.com/questions/20039659/…
  • 因为这是用于图像应用的,CreateMatrixMp 方法会运行 ((# of pixel)^2) 次。它在每个像素(节点)之间的边缘创建一个权重。
  • 除非我不理解这听起来像是通过将图像与内核进行卷积来解决的问题。我仍然不明白为什么需要数千个进程。
  • @paisanco 仅需要数千个进程,因为我想并行化它。该算法循环通过一个专注于单个像素的函数,然后在for 循环中将其与图像中的每个其他像素进行比较,为每个像素分配一个边缘值。然后在每个像素上执行。所以实际上只有(像素数)个进程,因为每个进程循环遍历整个图像。但是,对于成千上万的大图像。 “用内核卷积图像”是什么意思?
  • 您是否已经考虑过 IPython 的并行映射 (ipython.org/ipython-doc/dev/parallel/…)?

标签: python arrays numpy multiprocessing shared-memory


【解决方案1】:

欢迎来到多线程的黑暗世界。我认为您的大问题是 mgr.Array 将同步放在阵列周围。如果您快速生成数据,这将是一个瓶颈,因为进程将等待最后一个完成数组。如果每个进程都保留一个 num 数组的私有副本,它会更有效并且会有所帮助。输入所有数据后,请等待所有过程完成。然后您可以将所有数组组合到 self.data 中。这样,任何处理都不需要等待共享资源。此解决方案和您的解决方案都不能保证输出列表的顺序。我怀疑 self.numPixels 的顺序可能很重要。许多解决方案,但最简单的方法是按顺序输入数据并在完成后执行 self.data.sort(...) 。或者更快地,预先创建 self.data 并让进程将结果戳到正确的位置。 self.data 不需要是共享数据结构,因为进程永远不会改变任何共同点。如果数组映射到类 C 数组,则此方法有效。它不适用于链接列表等。希望这会有所帮助。询问您是否需要更多详细信息。

【讨论】:

  • 感谢您的回答。我同意最好有私有数组,一旦找到每个值,就在最后做一次大写。但我也同意这些过程永远不会改变任何共同点(至少它们不应该)。这是否意味着他们可以同时在不同的地方编辑数组,而无需等待?当我尝试像这样运行它时,出于某种原因,我得到一个充满零的数组,就好像进程正在擦除彼此的值一样。
  • 正如我最后评论的那样,它只适用于静态数组并且取决于 Python 实现。 NumPy 数组也是如此 - 除了它们与 Python 列表不同,因此可能会以不同的方式生成。这些进程不太可能(尽管并非不可能)擦除其他数据。您可能获得的是副本而不是对数据的引用。我不应该提到这种方法,因为它依赖于可能在系统(2.7v3、PyPy、CPython 或 Jython 等)之间改变的语言内部实现。话虽如此,它应该有效。
  • 当我遇到stackoverflow.com/questions/25938187/… 时,我只是整理了一个样本@ 一位受访者指出,我的建议适用于多线程,但不适用于多进程。后者是独立的,有自己的内存空间。有趣的是,最后一个响应引入了 multiprocessing.pool,如果没有另行说明,它会为每个 cpu 计数创建一个线程 - 类似于您的原始示例。
  • 我最终使用了Pool,它运行良好。感谢您的建议,我会将其标记为已回答。
猜你喜欢
  • 2021-05-04
  • 2013-04-05
  • 1970-01-01
  • 2012-12-15
  • 2021-09-23
  • 2019-04-02
  • 1970-01-01
  • 1970-01-01
  • 2016-04-21
相关资源
最近更新 更多