与 Boost.Python 相比,在 Cython 中扩展 NumPy 的相对优势是什么?

What are the relative advantages of extending NumPy in Cython vs Boost.Python?

我需要加快一些处理 NumPy 数组的算法。他们将使用 std::vector 和一些更高级的 STL 数据结构。

我已经将我的选择范围缩小到 Cython(它现在包装了大多数 STL 容器)和 Boost.Python(它现在内置了对 NumPy 的支持)。

根据我作为一名程序员的经验,我知道有时需要 个月 来使用一个框架来发现它隐藏的问题(因为它们很少被它的门徒用作谈话要点),所以你的帮助可能会为我节省很多时间。

与 Boost.Python 相比,在 Cython 中扩展 NumPy 的相对优势和劣势是什么?

对于小的一次性问题,我倾向于使用 cython,对于与 c++ 代码库的更大集成,更喜欢 boost Python。

部分取决于您的代码的受众。如果您正在与一个在 python 方面拥有丰富经验但使用 C++ 的经验很少的团队合作,那么 Cython 很有意义。如果你有一个固定的代码库,其中有复杂的类型可以互操作,boost python 最终可能会更便宜一些 运行.

Cython 鼓励您增量编写,根据需要逐渐添加类型以获得额外的性能并解决许多硬包装问题。 boost Python 需要付出大量努力来获得构建设置,并且很难生成在 PyPI

上有意义的包

Cython 有很好的内置错误 messages/diagnostics,但据我所知,boost 产生的错误可能很难解释 - 善待自己并使用 new-ish c++ 编译器,最好是一种以生成可读错误消息而闻名的编译器。

不要打折替代工具,如 numba(与 cython 的性能相似,代码为 Python,而不仅仅是看起来相似的东西)和 pybind11(提升 Python 没有提升并且错误更好消息)

这是一个非常不完整的答案,只涵盖了它的一小部分(如果我想到更多,我会编辑它):


提升doesn't look to implement operator[] specifically for numpy arrays。这意味着 operator[] 将来自基础 object class(ndarray 继承),这意味着调用将通过 Python 机制到达 __getitem__ 所以索引会很慢(接近 Python 速度)。如果你想快速索引,你必须自己做指针运算:

// rough gist - untested:

// i,j,k are your indices

double* data = reinterpret_cast<double*>(array.get_data());
// in reality you'd check the dtype - the data may not be a double...

double data_element = array.strides(0)*i + array.strides(1)*j +array.strides(2)*k;

相比之下,Cython 具有自动内置的 numpy 数组的高效索引。


Cython 不擅长 std::vector 之类的事情(尽管它并不是绝对糟糕 - 您通常可以欺骗它做您想做的事)。一个值得注意的限制是所有 cdef 都必须在函数的开头,因此 C++ class 会默认构造在那里,然后在稍后分配 to/manipulated (这可能有点低效).对于超出简单用途的任何事情,您不想在 Cython 中操作 C++ 类型(相反,最好用 C++ 编写代码然后从 Cython 调用它)。

第二个限制是它与 non-class 模板斗争。一个常见的示例是 std::array,它以数字为模板。根据您计划的代码,这可能是也可能不是问题。