我遇到了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
答案 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__
模块中查找该类,但是使用您的代码,它无法找到它,因为它位于函数内部。
但是,正如评论中所指出的那样,经理不应该被腌制,所以另一个对象必须将其拖入,例如在其全局中包含管理器的函数。