泡菜转储的多处理队列问题

吉尔莫特

我已经阅读并再次阅读了有关多处理模块和队列管理的Python文档,但是找不到与该问题相关的任何信息,这使我发疯并阻止了我的项目:

我写了一个'JsonLike'类,它允许我创建一个对象,例如:

a = JsonLike()
a.john.doe.is.here = True

...不考虑中间初始化(非常有用)

以下代码只是创建了一个这样的对象,将其设置并插入到数组中,然后尝试将其发送到进程(这是我所需要的,但是对象本身的发送会导致相同的错误

考虑这段代码:

from multiprocessing import Process, Queue, Event

class JsonLike(dict):
    """
    This class allows json-crossing-through creation and setting such as :
    a = JsonLike()
    a.john.doe.is.here = True
    it automatically creates all the hierarchy
    """

    def __init__(self, *args, **kwargs):
        # super(JsonLike, self).__init__(*args, **kwargs)
        dict.__init__(self, *args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.items():
                    self[k] = v
        if kwargs:
            for k, v in kwargs.items():
                self[k] = v

    def __getattr__(self, attr):
        if self.get(attr) != None:
            return attr
        else:
            newj = JsonLike()
            self.__setattr__(attr, newj)
            return newj

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        dict.__setitem__(self, key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        dict.__delitem__(self, key)
        del self.__dict__[key]


def readq(q, e):
    while True:
        obj = q.get()
        print('got')
        if e.is_set():
            break


if __name__ == '__main__':
    q = Queue()
    e = Event()

    obj = JsonLike()
    obj.toto = 1

    arr=[obj]

    proc = Process(target=readq, args=(q,e))
    proc.start()
    print(f"Before sending value :{arr}")
    q.put(arr)
    print('sending done')
    e.set()
    proc.join()
    proc.close()

我在上得到以下输出q.put

Before sending value :[{'toto': 1}]
Traceback (most recent call last):
sending done
  File "/usr/lib/python3.7/multiprocessing/queues.py", line 236, in _feed
    obj = _ForkingPickler.dumps(obj)
  File "/usr/lib/python3.7/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
TypeError: 'JsonLike' object is not callable

有什么建议?

醋酸纤维素

问题是,您正陷入困境__getattr__如果在此方法内添加一条print语句,您将看到运行以下代码也会导致崩溃:

obj = JsonLike()
obj.toto.test = 1

q = Queue()
q.put(obj)
q.get()

最后一条语句将导致(重复)调用obj.__getattr__,搜索名为的属性__getstate__(稍后将尝试查找其friend __setstate__)。这是泡菜文档中有关此dunder方法的内容:

如果__getstate__()不存在方法,则__dict__照常对实例进行酸洗。

在您的情况下,问题在于此方法不存在,但是您的代码使它看起来像它(通过动态创建具有正确名称的属性)。因此,不会触发默认行为,而是__getstate__会调用名为空属性问题在于这__getstate__不是一个可调用JsonLike对象,因为它是一个空对象。这就是为什么您可能会在这里看到诸如“无法调用JsonLike”之类的错误的原因。

一种快速的解决方法是避免触摸看起来像__xx__偶的属性_xx为此,您可以添加/修改以下行:

import re

dunder_pattern = re.compile("__.*__")
protected_pattern = re.compile("_.*")

class JsonLike(dict):

    def __getattr__(self, attr):
        if dunder_pattern.match(attr) or protected_pattern.match(attr):
            return super().__getattr__(attr)
        if self.get(attr) != None:
            return attr
        else:
            newj = JsonLike()
            self.__setattr__(attr, newj)
            return newj

这将使先前的代码正常工作(您的代码也是如此)。但是,另一方面,您将无法再编写类似的东西obj.__toto__ = 1,但这仍然是一件好事。

我觉得您可能会在其他情况下遇到类似的错误,可悲的是,在某些情况下,您会发现不会使用此类可预测属性名称的库。这就是为什么我不建议使用这种IRL机制的原因之一(尽管我真的很喜欢这个想法,而且我很乐意看到它能走多远)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章