import multiprocessing
class multiprocessing_issue:
def __init__(self):
self.test_mp()
def print_test(self):
print "TEST TEST TEST"
def test_mp(self):
p = multiprocessing.Pool(processes=4)
p.apply_async(self.print_test, args=())
print "finished"
if __name__ == '__main__':
multiprocessing_issue()
我在上面设置了一个简单的测试,创建一个类,使用应该打印apply_async
的函数调用"TEST TEST TEST"
。当我运行时,我看到"finished"
已打印,但它从未按预期打印"TEST TEST TEST"
。
在这个简单的测试用例中,有人能看到错误吗?我已将其设置为重现我在代码中使用它的方式。
Ubuntu上的Python 2.7
答案 0 :(得分:3)
修改test_mp
,如下所示:
def test_mp(self):
p = multiprocessing.Pool(processes=4)
r = p.apply_async(self.print_test, args=())
print r.get()
答案会更清楚。
Traceback (most recent call last):
File "test.py", line 18, in <module>
multiprocessing_issue()
File "test.py", line 6, in __init__
self.test_mp()
File "test.py", line 14, in test_mp
print r.get()
File "/usr/lib/python2.7/multiprocessing/pool.py", line 567, in get
raise self._value
cPickle.PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
实例方法cannot be serialized很容易。当序列化函数时,Pickle协议所做的只是将其转换为字符串。
In [1]: dumps(function)
Out[1]: 'c__main__\nfunction\np0\n.'
对于子进程,由于单独的进程地址空间,很难找到实例方法引用的正确对象。
dill之类的模块比Pickle做得更好。然而,我会阻止你混合并发和OOP,因为逻辑很容易混淆。
答案 1 :(得分:1)
啊,在进程之间移动类引用是一个问题,如果我在模块级而不是类级别定义方法一切正常。
import multiprocessing
class multiprocessing_issue:
def __init__(self):
self.test_mp()
def test_mp(self):
p = multiprocessing.Pool(4)
r = p.apply_async(mptest, args=())
r.get()
print "finished"
def mptest():
print "TEST TEST TEST"
if __name__ == '__main__':
multiprocessing_issue()