我遇到了多进程的问题,下面是我用来执行测试的代码:
import multiprocessing
class Test():
def __init__(self):
pass
def add(self,x,y):
self.x = x
self.y = y
return self.x + self.y
class Worker(Test):
def do_me(self,x,y):
return self.add(x,y)
if __name__ == '__main__':
job = Worker()
# #single process
# x = 1
# y = 9
# result = job.do_me(x,y)
# print "%2d +%2d = %2d "%(x,y,result)
#multiprocess
x = [1,2,3]
y = [9,7,5]
pool = multiprocessing.Pool(processes=4)
retults = [ pool.map(job.do_me, ((x[i], y[i]),)) for i in range(len(x)) ]
print results
对于单个过程,它将正常工作。但是,对于多进程,它没有。错误消息是:
cPickle.PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemet hod failed
我在这里搜索,但我不太了解机制。有人能给我更多帮助吗?欢呼声。
答案 0 :(得分:2)
正如错误所示,您无法挑选实例方法。问题是这一行:
pool.map(job.do_me, ((x[i], y[i]),)) for i in range(len(x))
这背后的机制是当map
函数将函数(第一个参数)发送给所有工作者时,它必须以某种方式将其序列化为数据,因此它使用一种称为的机制pickling。还有其他机制,这是Python中非常常见的机制。
当它试图挑选一个实例方法(特别是方法do_me
,类型为Worker
的实例)并将其发送到池中时(让工人知道他们采用什么方法&# 39;应该执行),它失败了。因为你不能腌制实例方法。
您可以通过将方法移动到模块级别(删除Worker
类)来解决此问题:
def do_me(test_instance):
return test_instance.add(x,y)
现在我们无法访问self
,因为我们正在使用明确发送的test_instance,因此此方法不会绑定到{{ 1}}类了...或换句话说 - 这不再是实例方法。现在请确保在计划时重新考虑所有因素。
Test
类应该在这个结构中有一些东西,以便将参数构造中的列表理解保持为Test
简单:
pool.map
Adn然后这样称呼它:
class Test():
def __init__(self, x, y):
self.x = x
self.y = y
def add(self,x,y):
return self.x + self.y
results = pool.map(do_me, [Test(x[i], y[i]) for i in range(len(x))])
import multiprocessing
class Test():
def __init__(self, x, y):
self.x = x
self.y = y
def add(self):
return self.x + self.y
def do_me(test_instance):
return test_instance.add()
if __name__ == '__main__':
x = [1,2,3]
y = [9,7,5]
pool = multiprocessing.Pool(processes=4)
results = pool.map(do_me, [Test(x[i], y[i]) for i in range(len(x))])
print results
已经返回pool.map
list
是 init 标识对象数据的标准位置(在您的情况下为x,y)。
函数__init__
正在使用的函数应用于iterable的每个项目,因此它应该是单参数函数(您可以使用元组,但您必须将其解包)。