使用多进程时出现奇怪的反序列化错误

3 投票
3 回答
4134 浏览
提问于 2025-04-15 17:18

我在使用多进程时遇到了以下错误:

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 个回答

0

我在C++、Java和Delphi中处理过线程安全的问题,但在Python中没有,所以我的意见仅供参考。

这个关于Python和线程安全的页面特别提到,给字典赋值是原子操作,并且是线程安全的。也许你提到的自定义类并不是线程安全的?如果你还是想在两个线程之间传递自定义容器类,可以尝试添加一些推荐的锁机制。

我觉得很有趣的是,其他搜索结果明确表示Python是完全线程安全的。Python的官方文档自己也提到,提供了锁和其他机制来帮助处理多线程应用,所以看起来网络上的信息并不总是正确的(这真的会发生吗??)。

这是另一个关于Python和线程安全的StackOverflow问题

2

我觉得这是一些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

3

试试用 pickle 模块,而不是 cPickle 模块。因为 pickle 是用纯 Python 写的,通常它能给出比 cPickle 更有用的错误信息。(不过有时候我不得不把 pickle.py 复制一份到本地,然后在出错的地方加几个调试的打印语句来找出问题。)

一旦你找到了问题,就可以再切换回 cPickle

(我对多进程模块不是很熟悉,所以不太确定是你在做序列化还是它在做。如果是它在做的话,最简单的方法是先对 multiprocessingthreading 模块进行一些修改,然后再导入它们:import sys, pickle; sys.modules['cPickle']=pickle

撰写回答