Python 多处理:共享内存和 pickle 问题
Python multiprocessing: shared memory and pickle issue
我过去已经做过一些多处理,但是这次,我想不出解决方法。
我知道我只能对位于模块顶层的函数进行 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
我已经知道了。我无法将多处理任务移至顶层,因为我需要访问共享数据。此外,我想保持较低的依赖项数量,因此我需要使用内置的多处理库。
我希望代码有意义。那么,如何在多处理中使用实例中的共享内存 space 呢?有没有办法将功能移动到顶层?
因为唯一可以 pickle 的函数是那些在顶层的函数(参见 documentation 的 pickle)并且 multiprocessing
想要 pickle 它你不得不把它放在顶层。您只需修改您的要求即可。
例如,您有函数的参数,为什么不提供共享数据?或者您可以将共享数据放在一个可 pickleable 的实例中,并将函数置于顶层(您仍然可以向顶层函数提供 class 实例)。
例如,如果您想将共享数据放在一个实例中,您可以简单地在顶层定义该方法,就好像它是一个普通方法一样(但将定义放在顶层):
def fubar(self):
return self.x
class C(object):
def __init__(self, x):
self.x = x
foo = fubar
c = C()
现在你可以泡菜了 fubar
。您可以将其称为 c.foo()
或 fubar(c)
,但您只能将其腌制为 pickle.dumps(fubar)
,因此当它被取消腌制并被调用时,它会在以后的方式中被调用,因此您必须提供 self
参数以及 p.map
中的其他参数(即 p.map(mp_star, zip(repeat(self), xs, ys, repeat(c))
)。你当然要确保 self
也是可腌制的。
我过去已经做过一些多处理,但是这次,我想不出解决方法。
我知道我只能对位于模块顶层的函数进行 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
我已经知道了。我无法将多处理任务移至顶层,因为我需要访问共享数据。此外,我想保持较低的依赖项数量,因此我需要使用内置的多处理库。
我希望代码有意义。那么,如何在多处理中使用实例中的共享内存 space 呢?有没有办法将功能移动到顶层?
因为唯一可以 pickle 的函数是那些在顶层的函数(参见 documentation 的 pickle)并且 multiprocessing
想要 pickle 它你不得不把它放在顶层。您只需修改您的要求即可。
例如,您有函数的参数,为什么不提供共享数据?或者您可以将共享数据放在一个可 pickleable 的实例中,并将函数置于顶层(您仍然可以向顶层函数提供 class 实例)。
例如,如果您想将共享数据放在一个实例中,您可以简单地在顶层定义该方法,就好像它是一个普通方法一样(但将定义放在顶层):
def fubar(self):
return self.x
class C(object):
def __init__(self, x):
self.x = x
foo = fubar
c = C()
现在你可以泡菜了 fubar
。您可以将其称为 c.foo()
或 fubar(c)
,但您只能将其腌制为 pickle.dumps(fubar)
,因此当它被取消腌制并被调用时,它会在以后的方式中被调用,因此您必须提供 self
参数以及 p.map
中的其他参数(即 p.map(mp_star, zip(repeat(self), xs, ys, repeat(c))
)。你当然要确保 self
也是可腌制的。