将接受类成员函数的函数传递给Python多进程pool.map()

7 投票
2 回答
6642 浏览
提问于 2025-04-17 13:21

你好,我今天早上一直在为这个问题苦恼,希望有人能给我一些指引。

这是我目前的代码:

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,而不是 picklecPickle,而 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]

获取代码请访问: https://github.com/uqfoundation/pathos

9

multiprocess模块使用pickle模块来把传给函数(f)的参数进行“打包”,然后在另一个进程中执行这个函数。

很多内置的数据类型都可以被“打包”,但实例方法是不能被“打包”的。所以像.05这样的数字是可以的,但像x.some_func1这样的函数就不行。想了解更多,可以查看什么可以被打包和解包?

没有简单的解决办法。你需要重新设计你的程序,让实例方法不需要作为参数传递(或者干脆不使用multiprocess)。

撰写回答