无法挑选<class'__main __。jobqueuemanager'=“”> </class>

时间:2014-09-02 19:51:31

标签: python multiprocessing pickle

我遇到了code中的可挑剔性问题(也在下面附上)。我已阅读相关帖子[1] [2],但我找不到有用的相关信息。你能否解释或解决这个错误?

下面是返回错误的代码部分:

pickle.PicklingError: Can't pickle <class '__main__.JobQueueManager'>: it's not found as __main__.JobQueueManager

谢谢!

def make_server_manager(port, authkey):

    job_q = Queue.Queue()
    result_q = Queue.Queue()

    class JobQueueManager(SyncManager):
        pass

    JobQueueManager.register('get_job_q', callable=lambda: job_q)
    JobQueueManager.register('get_result_q', callable=lambda: result_q)

    manager = JobQueueManager(address=('', port), authkey=authkey)
    manager.start()
    print 'Server started at port %s' % port
    return manager

PS:Python 2.7.7,Win 7

4 个答案:

答案 0 :(得分:3)

据我所知,要使此模式在Windows上运行,您需要创建一个可选择的queue.Queue。您可以通过创建定义__setstate__ and __getstate__Queue子类来实现这一点,并让它只腌制我们实际需要在进程之间发送的状态片段,并留下其他内容(不可拆卸的内部锁定)出来。

我们需要做的其他更改是将自定义Manager类定义移到顶层,而不是使用lambda函数作为callable的参数。相反,我们使用partial和顶级函数,因为它可以被腌制。这是最终的代码:

import sys
from multiprocessing.managers import SyncManager
from functools import partial
import multiprocessing
from Queue import Queue as _Queue

class Queue(_Queue):
    """ A picklable queue. """   
    def __getstate__(self):
        # Only pickle the state we care about
        return (self.maxsize, self.queue, self.unfinished_tasks)

    def __setstate__(self, state):
        # Re-initialize the object, then overwrite the default state with
        # our pickled state.
        Queue.__init__(self)
        self.maxsize = state[0]
        self.queue = state[1]
        self.unfinished_tasks = state[2]


def get_q(q):
    return q

class JobQueueManager(SyncManager):
    pass


def make_server_manager(port, authkey):
    job_q = Queue()
    result_q = Queue()

    job_q.put("hey")
    JobQueueManager.register('get_job_q', callable=partial(get_q, job_q))
    JobQueueManager.register('get_result_q', callable=partial(get_q, result_q))

    manager = JobQueueManager(address=('', port), authkey=authkey)
    #manager.start()
    print('Server started at port %s' % port)
    return manager

def make_client_manager(port, authkey):
    JobQueueManager.register('get_job_q')
    JobQueueManager.register('get_result_q')
    manager = JobQueueManager(address=('localhost', port), authkey=authkey)
    manager.connect()
    queue = manager.get_job_q()
    print("got queue {}".format(queue))
    print(queue.get_nowait())

if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == "--client":
        make_client_manager(50000, 'abcdefg')
    else:
        manager = make_server_manager(50000, "abcdefg")
        server = manager.get_server()
        server.serve_forever()

答案 1 :(得分:1)

您需要拥有Queue.Queue pickleable,以及lambda个功能和JobQueueManager

要做到这一点,我认为你可能会非常懒惰,而你需要做的就是获得dill包和import dill

我没有在Windows上测试,但它应该如下工作。 dill可在>>> import dill >>> import Queue >>> from multiprocessing.managers import SyncManager >>> >>> def make_server_manager(port, authkey): ... job_q = Queue.Queue() ... result_q = Queue.Queue() ... class JobQueueManager(SyncManager): ... pass ... JobQueueManager.register('get_job_q', callable=lambda: job_q) ... JobQueueManager.register('get_result_q', callable=lambda: result_q) ... manager = JobQueueManager(address=('',port), authkey=authkey) ... manager.start() ... print "server started at port %s" % port ... return manager ... >>> sm = make_server_manager(12345, 'foofoo') server started at port 12345 找到{/ 3}}。

{{1}}

答案 2 :(得分:1)

dt = datetime(DateString, 'InputFormat', 'yyyy/MM/dd HH:mm:SS'); dt.month 库为您提供了开箱即用的解决方案 - multiprocessing.Queue,应该可以在任何地方自动选择,即使在Windows上(并且可以在2.7之前工作)。

试图让multiprocessing可选择对我来说似乎是一个坏主意。您不会获得可以从两个不同进程使用的一个队列 - 您将在另一个进程中获得该队列的独立副本。

如果你想在另一个进程中拥有队列的当前状态的副本,那么将队列中的所有元素提取为一个简单的旧列表(免费的pickle)(如果所有元素都是如此)的工作要少得多是可选的),发送列表,然后在另一侧重新构建一个新的Queue.Queue

另外,正如我想象你现在已经发现的那样,你不能腌制当地的羔羊 - 这怎么会有效呢?相反,为该命名空间创建一个全局函数,并使用所需数据发送该全局函数。

答案 3 :(得分:0)

尝试:

class JobQueueManager(SyncManager):
        pass

def make_server_manager(port, authkey):

    job_q = Queue.Queue()
    result_q = Queue.Queue()

    JobQueueManager.register('get_job_q', callable=lambda: job_q)
    JobQueueManager.register('get_result_q', callable=lambda: result_q)

    manager = JobQueueManager(address=('', port), authkey=authkey)
    manager.start()
    print 'Server started at port %s' % port
    return manager

将类的定义移动到pickle可以找到它的位置应该允许酸洗。 Pickle将在__main__模块中查找该类,但是使用您的代码,它无法找到它,因为它位于函数内部。 但是,正如评论中所指出的那样,经理不应该被腌制,所以另一个对象必须将其拖入,例如在其全局中包含管理器的函数。