Pybind和Python C用法
C++不一定比Python运行快,在“起跑”阶段,C++甚至比Python要慢。我们使用C++主要是为了加速大段Python代码。
- 因为Python调用C++需要进行参数转换和返回值转换,这个也会耗费时间。
- Python的.会搜寻很多东西才能获得到对象的属性、方法等,也会影响执行速度。
- 虽然Python调用C++在类型转换上会有速度损失,但是在进入到函数提内运行过程中的速度是不影响的,假如我们的运算量够大,完全可以弥补那一点点性能影响,所以要想重复利用C++的速度,尽量少调用C++,把计算结果竟然一次性返回,而不是我们多次进行交互,这样就能最大化利用C++。
如何让你的Python更快 pybind github pybind11 文档 Python3: Python C API参考 Python2: Python C API参考
GIL的获取和释放
当Python端调用C++端的代码时,如果不在C++端主动释放GIL锁,该线程会一直hold GIL锁。
- Pybind用法:py::gil_scoped_release:释放GIL锁;py::gil_scoped_acquire:获取GIL锁
- Python C用法:可以使用Py_BEGIN_ALLOW_THREADS和Py_END_ALLOW_THREADS这一对宏来释放GIL Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS ;使用gstate = PyGILState_Ensure()和PyGILState_Release(gstate)来获取GIL。
Python对象
py::cast(返回转换后的py::object对象,是右值,不能对其做取地址操作)、obj.cast
Python types 包括handle, object, bool_, int_, float_, str, bytes, tuple, list, dict, slice, none, capsule, iterable, iterator, function, buffer, array, and array_t.
- handle: Holds a reference to a Python object (no reference counting)
- inc_ref(): increase the reference count of the Python object
- dec_ref(): decrease the reference count of the Python object
- object: Holds a reference to a Python object (with reference counting)
- array: https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html
ref_count(): Return the object’s current reference count.
Python调用C/C++函数
- 返回值:返回值策略
- 增加调用策略:call_guard<T>
- 参数:Python object可以直接作为参数(例如上面Python对象中的dict等);*args和**kwargs也可以作为参数(py::args起源于py::tuple,py::kwargs起源于py::dict);通过py::arg定义默认参数
智能指针
std::unique_ptr(不能作为参数)、std::shared_ptr 参考
The binding generator for classes, class_, can be passed a template type that denotes a special holder type that is used to manage references to the object. If no such holder type template argument is given, the default for a type named Type is std::unique_ptr
类
构造函数:
- py::init 参考
- 还有一种__init__函数。类似如下:
py::class_<Raster>(m, "Raster", py::buffer_protocol()) .def("__init__", [](Raster& raster, py::array_t<double> buffer, double spacingX, double spacingY, double spacingZ) { py::buffer_info info = buffer.request(); new (&raster) Raster3D(static_cast<double*>(info.ptr), info.shape[0], info.shape[1], info.shape[2], spacingX, spacingY, spacingZ); })
参考
其他可以提速Python方法:
相关PR: