Python多进程:共享内存和pickle问题

3

我之前已经做过一些多进程的工作,但这次我无法想出解决方法。

我知道只有在模块的顶层定义的函数才能被pickle。到目前为止这一直很好用,但现在我必须在一个实例中使用共享内存,我不知道如何将函数移动到顶层。

考虑以下情况

import numpy as np
import multiprocessing
from itertools import repeat

class Test:

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def my_task(self):

        # Create process pool
        p = multiprocessing.Pool(4)

        # Create shared memory arrays
        share1 = multiprocessing.Array("d", self.x, lock=False)
        share2 = multiprocessing.Array("d", self.y, lock=False)

        def mp(xc, yc, c):

            # This is just some random weird statement
            foo = np.sum(share1) + np.sum(share2) +xc + yc + c
            return foo


        def mp_star(args):
            return mp(*args)

        # Define some input for multiprocessing
        xs = [1,2,3,4,5]
        ys = [5,6,7,8,9]
        c = 10

        # Submit tasks
        result = p.map(mp_star, zip(xs, ys, repeat(c)))

        # Close pool
        p.close()

        return result



# Get some input data
x = np.arange(10)
y = x**2

# Run the thing
cl = Test(x=x, y=y)
cl.my_task()

你可以看到,我需要从实例中访问共享数据。出于这个原因,我把多进程部分放在'my_task'方法内。由于这个原因,我会得到典型的pickle错误。

_pickle.PicklingError: Can't pickle <function Test.my_task.<locals>.mp_star at 0x10224a400>: attribute lookup mp_star on __main__ failed

我已经知道了其中的内容。但是我不能将多进程任务移动到顶层,因为我需要访问共享数据。此外,我希望保持依赖项的数量较低,因此需要使用内置的多进程库。

希望代码有意义。那么,如何在多进程实例中使用共享内存空间?是否有一种方法可以将函数移动到顶层?

1个回答

2

由于只有顶层函数才能被pickle(请参阅pickle的文档),而multiprocessing想要pickle它,所以您必须将其放在顶层。您只需要重新调整您的需求。

例如,如果您有函数参数,为什么不提供共享数据?或者您可以将共享数据放在可pickle的实例中,并使函数位于顶层(仍然可以向顶层函数提供类实例)。

例如,如果您想将共享数据放在实例中,您可以简单地将方法定义为顶层方法,就像普通方法一样(但将定义放在顶层):

def fubar(self):
    return self.x

class C(object):
     def __init__(self, x):
          self.x = x

     foo = fubar

c = C()

现在你可以使用pickle来序列化fubar。你可以将其称为c.foo()fubar(c),但是你只能将其pickle为pickle.dumps(fubar),因此当它被反序列化并调用时,它将期望以后一种方式被调用,因此您必须在p.map中提供self参数以及其他参数(即p.map(mp_star, zip(repeat(self), xs, ys, repeat(c)))。当然,您还必须确保self也是可被pickle的。


嗨,谢谢你的回答。我现在已经这样实现了,我只是跳过了共享内存部分。我只是使用itertools.repeat传递数组。我的主要关注点是内存使用,因为我有相当大的数组,但目前看来这不是一个问题。 - HansSnah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接