Python NotImplementedError:池对象不能在进程之间传递

时间:2014-08-19 11:38:55

标签: python multiprocessing pool

当页面附加到页面列表时,我正在尝试传递工作,但我的代码输出返回NotImplementedError。以下是我正在尝试做的代码:

代码:

from multiprocessing import Pool, current_process
import time
import random
import copy_reg
import types
import threading


class PageControler(object):
    def __init__(self):
        self.nProcess = 3
        self.pages = [1,2,3,4,5,6,7,8,9,10]
        self.manageWork()


    def manageWork(self):

        self.pool = Pool(processes=self.nProcess)

        time.sleep(2)
        work_queue = threading.Thread(target=self.modifyQueue)
        work_queue.start()

        #pool.close()
        #pool.join()

    def deliverWork(self):    
        if self.pages != []:
            pag = self.pages.pop()
            self.pool.apply_async(self.myFun)


    def modifyQueue(self):
        t = time.time()
        while (time.time()-t) < 10:
            time.sleep(1)
            self.pages.append(99)
            print self.pages
            self.deliverWork()

    def myFun(self):
        time.sleep(2)


if __name__ == '__main__':
    def _pickle_method(m):
        if m.im_self is None:
            return getattr, (m.im_class, m.im_func.func_name)
        else:
            return getattr, (m.im_self, m.im_func.func_name)

    copy_reg.pickle(types.MethodType, _pickle_method)

    PageControler()

输出:

NotImplementedError: pool objects cannot be passed between processes or pickled

是否可以在进程之间传递池对象?

修改

我正在使用Python 2.6

2 个答案:

答案 0 :(得分:25)

为了挑选您尝试传递给Pool的实例方法,Python需要挑选整个PageControler对象,包括其实例变量。其中一个实例变量是Pool对象本身,而Pool个对象无法被腌制,因此会出错。您可以通过在对象上实现__getstate__来解决此问题,并使用它在酸洗之前从实例中删除pool对象:

class PageControler(object):
    def __init__(self):
        self.nProcess = 3
        self.pages = [1,2,3,4,5,6,7,8,9,10]
        self.manageWork()


    def manageWork(self):

        self.pool = Pool(processes=self.nProcess)

        time.sleep(2)
        work_queue = threading.Thread(target=self.modifyQueue)
        work_queue.start()

        #pool.close()
        #pool.join()

    def deliverWork(self):    
        if self.pages != []:
            pag = self.pages.pop()
            self.pool.apply_async(self.myFun)


    def modifyQueue(self):
        t = time.time()
        while (time.time()-t) < 10:
            time.sleep(1)
            self.pages.append(99)
            print self.pages
            self.deliverWork()

    def myFun(self):
        time.sleep(2)

    def __getstate__(self):
        self_dict = self.__dict__.copy()
        del self_dict['pool']
        return self_dict

    def __setstate__(self, state):
        self.__dict__.update(state)

__getstate__总是在腌制对象之前调用,并允许您准确指定对象的状态应该实际被腌制。然后在取消修改时,__setstate__(state)将被调用(如果它是在我们的情况下),或者如果不是,则dict返回的__getstate__将被用作对于未打开的实例,__dict__。在上面的示例中,我们明确地将__dict__设置为我们在dict中返回的__getstate__,但我们可能没有实现__setstate__并获得相同的效果

答案 1 :(得分:1)

如果必须将整个对象传递给流程,Dano的答案是一个很好的方法。在您的情况下,您传递给池的函数不需要对类实例的引用。所以另一种方法是使用@staticmethod装饰器使函数成为静态方法。如果函数确实需要引用一个或两个类成员变量,那么它们可以作为只读变量的参数传入,如果还需要写入则在回调中更新(当然,如果你想要,你需要这样做)在任何情况下都更新本地类实例。)

例如:

Class A(object):

    def __init__(self):
        self._pool = multiprocessing.Pool(1)
        self.member_variable = 1

    @staticmethod
    def MyFunc(variable):
        variable += 1
        return variable

    def Callback(self, return_val):
        self.member_variable = return_val

    def CallFuncAsync(self):
        pool.apply_async(self.MyFunc, (self.member_variable,), callback=self.Callback)