【问题标题】:python bytearray to C++ objectpython bytearray 到 C++ 对象
【发布时间】:2021-06-02 14:08:25
【问题描述】:

我想知道是否可以得到一些帮助。对于上下文,我正在使用一些 C++ 库来生成一些我想通过网络从服务器发送到客户端的大型(想想数百 Mb)对象。

在服务器上,我有以下内容:

PyObject*  CKKSwrapper::SerializePrivateKey() {
    std::string s;
    std::ostringstream os(s);
    Serial::Serialize(m_keys.publicKey, os, SerType::BINARY);

    auto msg = os.str();
    return PyBytes_FromString(&msg[0]);
}

这给了我一些 Python 对象。然后我通过 python 套接字将它直接发送给客户端。我正在阅读它

def _safe_recv_abstract(socket: Socket, deserializer_func):
    expected_length = _get_obj_size(socket)
    running_length = 0
    running_msg = bytearray()
    while running_length < expected_length:
        msg = socket.recv(expected_length)
        if msg:
            running_msg = cppwrapper.Accumulator(running_msg, bytearray(msg))
            running_length += len(msg)

    socket.send(_add_header_to_payload(b"ACK"))
    logger.debug("_safe_recv_unenc_obj: Received all data")
    if optional_pycrypto_deserialize_func:
        return deserializer_func(running_msg)
    return running_msg

两件事:

  1. 累加器(来自上面的cppwrapper.Accumulator())看起来像
PyObject* CKKSwrapper::Accumulator(PyObject a, PyObject b){
    return PyByteArray_Concat(&a, &b);
}
  1. deserializer_func 调用的底层 C++ 函数看起来像
void CKKSwrapper::DeserializeX(
    const boost::python::list &pyvals) {

    auto msg= pythonListToCppVectorBytes(pyvals);

    LPPrivateKey<DCRTPoly> sk;
    std::istringstream is(string(msg.begin(), msg.end()));
    Serial::Deserialize(sk, is, SerType::BINARY);

    this->m_keys.secretKey = sk;
}

我遇到了以下错误:

Boost.Python.ArgumentError: Python argument types in
    CKKSwrapper.Accumulator(bytearray, bytearray)
did not match C++ signature:
    Accumulator(pycrypto::CKKSwrapper {lvalue}, _object*, _object*)

我完全理解它在说什么并且类型是错误的,但我不确定为什么。来自docs

PyObject* PyByteArray_Concat(PyObject *a, PyObject *b)
    Return value: New reference.

    Concat **bytearrays** a and b and return a new bytearray with the result.

如果我理解正确,我正在传递字节数组,但它说它正在等待对象?

我尝试这样做的原因是当我使用字节数组或列表进行累积时,即

while running_length < expected_length:
    msg = socket.recv(expected_length)
    if msg:
        running_msg = cppwrapper.Accumulator(running_msg, bytearray(msg))
        running_length += len(msg)

内存使用和运行时间爆炸

【问题讨论】:

  • 所以,如果我理解正确的话:C++ 代码将一些 Blob 传递给 Python 代码,Python 代码通过网络套接字将其发送到另一块 Python 代码,然后将 Blob 传递回接收者。嗯……为什么?那完成了什么,不能简单地通过让 C++ 在同一个套接字上发送相同的 blob 来完成,它本身,由接收器上的 C++ 直接接收? Python 在这里做什么?
  • 好问题!这是因为遗留代码已经在 python 中,我只是在这里试图加快速度。 python 中还有很多其他功能我还不能迁移

标签: python c++ python-c-api pyobject


【解决方案1】:

简单错误的部分答案:

PyObject* CKKSwrapper::Accumulator(PyObject a, PyObject b)

这应该是

PyObject* CKKSwrapper::Accumulator(PyObject* a, PyObject* b)

PyObject从不按值传递,始终按指针传递。在实践中,所有有用的 Python 对象看起来像:

struct Something{
    PyObject ob_base;
    Useful data;
};

这本质上是 C++ 继承的 C 版本。通过按值传递,除了 ob_base 之外,您将丢失所有内容,就像按值传递 C++ 派生类作为其基类一样。

【讨论】:

  • 啊,明白了。我实际上最初尝试过,但遇到了同样的问题。我忘记改回来了。
  • 恐怕我对 Boost Python 的了解不足以帮助解决这个问题(因此是“部分答案”)
猜你喜欢
  • 2014-04-19
  • 2011-04-14
  • 2016-08-15
  • 2020-09-29
  • 2021-07-01
  • 1970-01-01
  • 2012-05-30
  • 2019-08-07
  • 1970-01-01
相关资源
最近更新 更多