C++ 对 Python 的扩展——安全的内存访问和内存布局

Posted

技术标签:

【中文标题】C++ 对 Python 的扩展——安全的内存访问和内存布局【英文标题】:C++ extension to Python - safe memory access, and memory layout 【发布时间】:2020-01-07 09:24:56 【问题描述】:

我正在使用作用于 Numpy 数组(非常大)的 c++ 函数来扩展 python 代码。 由于遗留问题,我目前同时拥有 PyBind 和 Python API 函数,都适用于 Python 3.6 及更高版本。 一旦我通过 ptr 访问内存,我很想确保内存布局与此 ptr 下的 c++ 数组完全对应。 我发现在这两种情况下,转置数组在 ptr 中的内容完全相同。我还发现通过 Python API 发送的子数组在 c++ 中给出的 ptr 与完整数组完全相同。在开发和测试的过程中,我还观察到了更多我认为奇怪的例子,但不能再重现它们了。 到目前为止,我在互联网上找不到任何食谱。我的解决方案是在 Python 中复制所有输入数组,例如 f(a.copy(), b.copy())

它似乎运作良好。 这是最佳/充分的解决方案吗? 我对如何生成输入数组没有任何限制。转置、子阵列、重塑,任意组合。

【问题讨论】:

你检查过使用 Pybind 的缓冲协议吗? pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html 内存布局正好对应c++数组是什么意思?你想避免什么情况? PyBind11 代码正在使用 NDArray xja(xj); xja.ptr 据我了解,这就是 Matt 的链接模板 struct NDArray NDArray(py::array_t &X) auto buf=X.request(); ndim=buf.ndim;大小=缓冲区大小; for (int d=0; d 对不起,格式很糟糕,但我所有的换行符似乎都消失了。 @Vladimir:回复帖子评论的正确方法通常是编辑帖子以包含新信息。 【参考方案1】:

使用 pybind11,您可以使用 py::array::c_style 标志,如 Matt Eding 的链接中所述。 Numpy 的 C API 通过 NPY_ARRAY_C_CONTIGUOUS 标志提供了几乎相同的功能。无论哪种情况,如果需要满足布局要求,数组将被隐式复制;如果您更愿意拒绝此类参数(以避免沉默的低效率),您必须自己检查数组的 flags

【讨论】:

这太棒了!谢谢,正是我想要的。我被默认的 np 数组在 python 中具有 c 传染性这一事实蒙蔽了双眼。 也许是一个相关的问题?我相信我没有错过链接页面;)这一切原则上是否意味着通过修改输入的返回变量将值从 c++ 返回到 python 是危险的?如果我不能在同一个地方累积类似MC的块的结果并且需要在每个块上分配...... @Vladimir:许多 Python 类型应该是不可变的;对于ndarray,可写性只是另一个可能强制复制的标志。

以上是关于C++ 对 Python 的扩展——安全的内存访问和内存布局的主要内容,如果未能解决你的问题,请参考以下文章

从 python 传递到 C++ 的数组中未映射的内存访问

单例模式

使用pybind11开发python扩展库

如何使用纯 Python 扩展 API (python3) 包装 C++ 对象?

单例模式

如何在 Python 进程中访问由 C++ 进程创建的互斥锁?