将多处理与使用 C++ class 作为基础 class 的 python 对象一起使用时 __init__ 中缺少参数
missing arguments in __init__ when using using multiprocessing with a python object that uses a C++ class as base class
我在 C++ 中有一个 class 节点,我使用 Boost/Python 暴露给 python (是的,我知道节点很小,但我翻译了它,因为一些相当大 classes 派生自它)。根据boost/python documentation,如果我实施getstate_manages_dict
,我应该能够做到这一点。这是我用来复制错误的最少代码量:
头文件:
class Node{
public:
Node(boost::python::object position);
~Node();
boost::python::object _position;
};
// pickle support for Node
struct node_pickle_suite : boost::python::pickle_suite{
static boost::python::tuple getinitargs(Node const& node){
return boost::python::make_tuple(node._position);
}
static boost::python::tuple getstate(boost::python::object obj)
{
Node& node = boost::python::extract<Node&>(obj);
return boost::python::make_tuple(obj.attr("__dict__"));
}
static void setstate(boost::python::object obj, boost::python::tuple state)
{
Node& node = boost::python::extract<Node&>(obj);
boost::python::dict d = extract<dict>(obj.attr("__dict__"));
d.update(state[0]);
}
static bool getstate_manages_dict() { return true; }
};
cpp 文件:
#include "node.h"
using namespace std;
Node::Node(boost::python::object position){
this->_position = position;
}
Node::~Node(){
}
BOOST_PYTHON_MODULE(Node){
class_<Node>("Node", init<boost::python::object>())
.def_readwrite("_position", &Node::_position)
.def_pickle(node_pickle_suite());
}
在python中,我有一个class以Node为基础class,还有一个进程需要将一些TestNodes放入队列中。虽然 q.put
有效,但 q.get
无效:
class Position:
def __init__(self, i, j ,k):
self._i = i
self._j = j
self._k = k
class TestNode(Node):
def __init__(self, position, l, m, n):
super().__init__(position)
self.l = l
self.m = m
self.n = n
self.c = {}
self.d = {}
self.dq = deque()
from multiprocessing import Process, Queue
def do_stuff(q):
for i in range(100):
pos = Position(1,2,3)
tn = TestNode(pos, 10, "hello", "world")
q.put(tn)
processes = []
q = Queue()
for i in range(3):
processes.append(Process(target=do_stuff, args=(q,)))
for process in processes:
process.start()
# the program crashes when this is called
a = q.get()
for process in processes:
process.join()
错误信息(更改路径以避免泄露个人信息):
File "path/testNode.py", line 34, in <module>
a = q.get()
File "path/lib/python3.7/multiprocessing/queues.py", line 113, in get
return _ForkingPickler.loads(res)
TypeError: __init__() missing 3 required positional arguments: 'l', 'm', and 'n'
这不会对纯 python 代码造成任何问题,或者如果我只是将一个 Node 对象放入队列,只有 class 继承自 Node 的对象。任何人都知道如何解决它?此外,我找不到任何特定于此类问题的内容,因此任何其他文档也会很有用。
谢谢
想通了:
似乎从 C++ 继承会破坏纯 Python 类 附带的 pickle 支持。我需要在 TestNode
:
中添加以下方法
__getinitargs__(self), __getstate__(self), __setstate__(self, state)
我在 C++ 中有一个 class 节点,我使用 Boost/Python 暴露给 python (是的,我知道节点很小,但我翻译了它,因为一些相当大 classes 派生自它)。根据boost/python documentation,如果我实施getstate_manages_dict
,我应该能够做到这一点。这是我用来复制错误的最少代码量:
头文件:
class Node{
public:
Node(boost::python::object position);
~Node();
boost::python::object _position;
};
// pickle support for Node
struct node_pickle_suite : boost::python::pickle_suite{
static boost::python::tuple getinitargs(Node const& node){
return boost::python::make_tuple(node._position);
}
static boost::python::tuple getstate(boost::python::object obj)
{
Node& node = boost::python::extract<Node&>(obj);
return boost::python::make_tuple(obj.attr("__dict__"));
}
static void setstate(boost::python::object obj, boost::python::tuple state)
{
Node& node = boost::python::extract<Node&>(obj);
boost::python::dict d = extract<dict>(obj.attr("__dict__"));
d.update(state[0]);
}
static bool getstate_manages_dict() { return true; }
};
cpp 文件:
#include "node.h"
using namespace std;
Node::Node(boost::python::object position){
this->_position = position;
}
Node::~Node(){
}
BOOST_PYTHON_MODULE(Node){
class_<Node>("Node", init<boost::python::object>())
.def_readwrite("_position", &Node::_position)
.def_pickle(node_pickle_suite());
}
在python中,我有一个class以Node为基础class,还有一个进程需要将一些TestNodes放入队列中。虽然 q.put
有效,但 q.get
无效:
class Position:
def __init__(self, i, j ,k):
self._i = i
self._j = j
self._k = k
class TestNode(Node):
def __init__(self, position, l, m, n):
super().__init__(position)
self.l = l
self.m = m
self.n = n
self.c = {}
self.d = {}
self.dq = deque()
from multiprocessing import Process, Queue
def do_stuff(q):
for i in range(100):
pos = Position(1,2,3)
tn = TestNode(pos, 10, "hello", "world")
q.put(tn)
processes = []
q = Queue()
for i in range(3):
processes.append(Process(target=do_stuff, args=(q,)))
for process in processes:
process.start()
# the program crashes when this is called
a = q.get()
for process in processes:
process.join()
错误信息(更改路径以避免泄露个人信息):
File "path/testNode.py", line 34, in <module>
a = q.get()
File "path/lib/python3.7/multiprocessing/queues.py", line 113, in get
return _ForkingPickler.loads(res)
TypeError: __init__() missing 3 required positional arguments: 'l', 'm', and 'n'
这不会对纯 python 代码造成任何问题,或者如果我只是将一个 Node 对象放入队列,只有 class 继承自 Node 的对象。任何人都知道如何解决它?此外,我找不到任何特定于此类问题的内容,因此任何其他文档也会很有用。
谢谢
想通了:
似乎从 C++ 继承会破坏纯 Python 类 附带的 pickle 支持。我需要在 TestNode
:
__getinitargs__(self), __getstate__(self), __setstate__(self, state)