使用多进程时出现奇怪的反序列化错误
我在使用多进程时遇到了以下错误:
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python2.6/threading.py", line 525, in __bootstrap_inner
self.run()
File "/usr/lib/python2.6/threading.py", line 477, in run
self.__target(*self.__args, **self.__kwargs)
File "/usr/lib/python2.6/multiprocessing/pool.py", line 282, in _handle_results
task = get()
UnpicklingError: NEWOBJ class argument has NULL tp_new
我完全不知道这是什么意思,虽然听起来像是C语言层面出了问题。有没有人能给我解释一下?
更新: 好吧,我找到了修复这个问题的方法。但我还是有点困惑。我正在返回这个类的一个实例:
class SpecData(object):
def __init__(self, **kwargs):
self.__dict__.update(**kwargs)
def to_dict(self):
return self.__dict__
如果我返回这个对象的实例,就会出现错误。但是,如果我调用 to_dict
并返回一个字典,就可以正常工作。我到底哪里做错了?
3 个回答
我在C++、Java和Delphi中处理过线程安全的问题,但在Python中没有,所以我的意见仅供参考。
这个关于Python和线程安全的页面特别提到,给字典赋值是原子操作,并且是线程安全的。也许你提到的自定义类并不是线程安全的?如果你还是想在两个线程之间传递自定义容器类,可以尝试添加一些推荐的锁机制。
我觉得很有趣的是,其他搜索结果明确表示Python是完全线程安全的。Python的官方文档自己也提到,提供了锁和其他机制来帮助处理多线程应用,所以看起来网络上的信息并不总是正确的(这真的会发生吗??)。
我觉得这是一些Python函数在可选取和不可选取方面的问题。可以看看这篇文章:
http://khinsen.wordpress.com/2012/02/06/teaching-parallel-computing-in-python/
我在使用django-celery(它使用了多进程模块)时也遇到过类似的问题。如果我的任务代码抛出了一些无法被选取的错误,这种多进程/选取的异常会让信息变得模糊。因为我还没有找到更好的方法来传播这些错误,所以我只能在我的任务代码中使用调试日志来追踪问题。我可能应该更聪明一点,注意我传递到队列中的内容(避免把异常放到消息队列中,这样多进程模块就不会尝试去选取或反选取它们)。
在你上面的例子中,你可能需要确保 SpecData.__dict__
是可以被选取的。可以参考这个链接:http://docs.python.org/library/pickle.html#pickle-protocol
试试用 pickle
模块,而不是 cPickle
模块。因为 pickle
是用纯 Python 写的,通常它能给出比 cPickle
更有用的错误信息。(不过有时候我不得不把 pickle.py
复制一份到本地,然后在出错的地方加几个调试的打印语句来找出问题。)
一旦你找到了问题,就可以再切换回 cPickle
。
(我对多进程模块不是很熟悉,所以不太确定是你在做序列化还是它在做。如果是它在做的话,最简单的方法是先对 multiprocessing
或 threading
模块进行一些修改,然后再导入它们:import sys, pickle; sys.modules['cPickle']=pickle
)