类中的multiprocessing.apply_async(myfunc,...)似乎不会调用myfunc

时间:2017-04-26 16:43:50

标签: python asynchronous multiprocessing

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

2 个答案:

答案 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()