将接受类成员函数的函数传递给Python多进程pool.map()
你好,我今天早上一直在为这个问题苦恼,希望有人能给我一些指引。
这是我目前的代码:
def f(tup):
return some_complex_function(*tup)
def main():
pool = Pool(processes=4)
#import and process data omitted
_args = [(x.some_func1, .05, x.some_func2) for x in list_of_some_class]
results = pool.map(f, _args)
print results
我遇到的第一个错误是:
> Exception in thread Thread-2: Traceback (most recent call last):
> File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner
> self.run() File "/usr/lib/python2.7/threading.py", line 504, in run
> self.__target(*self.__args, **self.__kwargs) File "/usr/lib/python2.7/multiprocessing/pool.py", line 319, in
> _handle_tasks
> put(task) PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
任何帮助都将非常感谢。
2 个回答
3
如果你使用一个叫做 pathos.multiprocessing
的库,它是 multiprocessing
的一个分支,你就可以在 multiprocessing 的 map
函数中直接使用类和类的方法。这是因为它使用了 dill
,而不是 pickle
或 cPickle
,而 dill
能够序列化几乎所有的 Python 对象。
pathos.multiprocessing
还提供了一个异步的 map 函数……而且它可以处理多个参数的 map
函数(例如 map(math.pow, [1,2,3], [4,5,6])
)。
你可以查看以下链接了解更多信息: multiprocessing 和 dill 可以一起做什么?
还有: http://matthewrocklin.com/blog/work/2013/12/05/Parallelism-and-Serialization/
>>> from pathos.multiprocessing import ProcessingPool as Pool
>>>
>>> p = Pool(4)
>>>
>>> def add(x,y):
... return x+y
...
>>> x = [0,1,2,3]
>>> y = [4,5,6,7]
>>>
>>> p.map(add, x, y)
[4, 6, 8, 10]
>>>
>>> class Test(object):
... def plus(self, x, y):
... return x+y
...
>>> t = Test()
>>>
>>> p.map(Test.plus, [t]*4, x, y)
[4, 6, 8, 10]
>>>
>>> p.map(t.plus, x, y)
[4, 6, 8, 10]
9
multiprocess
模块使用pickle
模块来把传给函数(f
)的参数进行“打包”,然后在另一个进程中执行这个函数。
很多内置的数据类型都可以被“打包”,但实例方法是不能被“打包”的。所以像.05
这样的数字是可以的,但像x.some_func1
这样的函数就不行。想了解更多,可以查看什么可以被打包和解包?
没有简单的解决办法。你需要重新设计你的程序,让实例方法不需要作为参数传递(或者干脆不使用multiprocess
)。