首页 > 解决方案 > 如何腌制/序列化 swigpyobject?

问题描述

我正在开发一个与内核模块连接的应用程序。对于这种通信,我在 python 中使用 netlink libnl3.5.0,它使用 swig 将“c”包装到 py 中。问题是当我尝试进行多处理并尝试将 msg 队列共享给不同的进程时。Python 无法腌制/序列化 SwigPyObject 格式的消息。

我试图找到这个对象的高级类实现,但我很困惑。看到其他帖子说要在对象中实现一些getstatereduce函数,但我不明白在哪里使用它。

尝试过 dill 包,但我猜 dill 正在使用 pickle 进行底层实现。所以这将返回相同的错误。

以下是我实施的主要部分

def queue_packet(msg,args):
    global a
    nlh=nl.nlmsg_hdr(msg)
    ghdr=genl.genlmsg_hdr(nlh)
    if(ghdr.cmd==2):
        _,attr=genl.py_genlmsg_parse(nlh,0,8,None)
        a.put(attr)
        #print(a.qsize())
    return 0

def worker(a):
    print("worker started")
    while True:
        if a.qsize()==0:
            continue
        attr=a.get()
        process_messages_cb(attr)
        a.task_done()
    return 0
a=multiprocessing.Manager.Queue()
while 1:
   nl.nl_recvmsgs(s,rx_cb)

这是接收消息并将消息放入队列的主要部分。并且不同的工作人员将从队列中获取消息并进一步处理它们。那么如何将消息放入队列以在不同的工作人员/子进程之间共享。我正在使用这个https://github.com/thom311/libnl/tree/master/python API。

谢谢

标签: picklepython-multiprocessingswignetlinkdill

解决方案


对于一个可拾取的对象,它需要实现一个__getstate__和一个__setstate__函数。

我通常做的是以下(在你的接口文件的末尾)。假设该对象MyObject是您使用 SWIG 包装的对象,其包装器不可拾取。

#pragma once
class MyOBject {
 public:
  MyObject() {}
  SetA(float a) {m_a = a;}
  SetB(float b) {m_b = b;}
 private:
  float m_a;
  float m_b;
};

然后在你的接口文件中,执行以下操作

%extend MyObject {
%pythoncode %{
def __getstate__(self):
  args = (a, b)
  return args
def __setstate__(self, state)
  self.__init__() # construct object
  (a,b) = state
  self.SetA(a)
  self.SetB(b)
%}
}

要使对象成为可挑选对象,您必须能够(以某种方式)从序列化数据中恢复它。在上面的示例中,通过调用一对函数进行恢复。在您的情况下,您需要找到一种方法来序列化对象的状态并从序列化数据中重新创建它。

这显示了如何制作包装器以使对象变得可拾取,但这需要您更改 libnl 的包装器

另一种选择是将传递的 python 对象包装在您为其实现__getstate____setstate__. 这个想法是一样的,你需要能够序列化和恢复你的对象的状态。我不确定这两种方法中哪一种是最简单的。


推荐阅读