[英]Fast conversion of C/C++ vector to Numpy array
我正在使用SWIG将一些C ++代码粘合到Python(2.6)上,并且该粘合剂的一部分包括一段代码,它将大数据字段(数百万个值)从C ++端转换为Numpy数组。 我能想出的最好的方法是为类实现一个迭代器,然后提供一个Python方法:
def __array__(self, dtype=float):
return np.fromiter(self, dtype, self.size())
问题是每个迭代器的next
调用都非常昂贵,因为它必须通过大约三到四个SWIG包装器。 这需要太长时间。 我可以保证C ++数据是连续存储的(因为它们存在于std :: vector中),并且感觉Numpy应该能够指向该数据的开头以及它包含的值的数量,并且直接阅读。
有没有办法将指向internal_data_[0]
和值internal_data_.size()
传递给numpy,以便它可以直接访问或复制数据而不需要所有的Python开销?
您将需要定义__array_interface__()
。 这将允许您直接传回指针和形状信息。
也许有可能使用f2py而不是swig。 尽管它的名字,它能够连接python与C以及Fortran。 见http://www.scipy.org/Cookbook/f2py_and_NumPy
优点是它可以自动处理到numpy数组的转换。
两个警告:如果你还不知道Fortran,你可能会发现f2py有点奇怪; 我不知道它与C ++有多好用。
如果将向量包装在实现Pythons Buffer Interface的对象中,则可以将其传递给numpy数组进行初始化(请参阅docs ,第三个参数)。 我敢打赌,这种初始化要快得多,因为它只能使用memcpy
来复制数据。
因此,看起来唯一真正的解决方案是基于pybuffer.i
,可以从C ++复制到现有缓冲区。 如果将其添加到SWIG包含文件:
%insert("python") %{
import numpy as np
%}
/*! Templated function to copy contents of a container to an allocated memory
* buffer
*/
%inline %{
//==== ADDED BY numpy.i
#include <algorithm>
template < typename Container_T >
void copy_to_buffer(
const Container_T& field,
typename Container_T::value_type* buffer,
typename Container_T::size_type length
)
{
// ValidateUserInput( length == field.size(),
// "Destination buffer is the wrong size" );
// put your own assertion here or BAD THINGS CAN HAPPEN
if (length == field.size()) {
std::copy( field.begin(), field.end(), buffer );
}
}
//====
%}
%define TYPEMAP_COPY_TO_BUFFER(CLASS...)
%typemap(in) (CLASS::value_type* buffer, CLASS::size_type length)
(int res = 0, Py_ssize_t size_ = 0, void *buffer_ = 0) {
res = PyObject_AsWriteBuffer($input, &buffer_, &size_);
if ( res < 0 ) {
PyErr_Clear();
%argument_fail(res, "(CLASS::value_type*, CLASS::size_type length)",
$symname, $argnum);
}
$1 = ($1_ltype) buffer_;
$2 = ($2_ltype) (size_/sizeof($*1_type));
}
%enddef
%define ADD_NUMPY_ARRAY_INTERFACE(PYVALUE, PYCLASS, CLASS...)
TYPEMAP_COPY_TO_BUFFER(CLASS)
%template(_copy_to_buffer_ ## PYCLASS) copy_to_buffer< CLASS >;
%extend CLASS {
%insert("python") %{
def __array__(self):
"""Enable access to this data as a numpy array"""
a = np.ndarray( shape=( len(self), ), dtype=PYVALUE )
_copy_to_buffer_ ## PYCLASS(self, a)
return a
%}
}
%enddef
然后你可以制作一个容器“Numpy” - 用
%template(DumbVectorFloat) DumbVector<double>;
ADD_NUMPY_ARRAY_INTERFACE(float, DumbVectorFloat, DumbVector<double>);
然后在Python中,只需:
# dvf is an instance of DumbVectorFloat
import numpy as np
my_numpy_array = np.asarray( dvf )
这只需要单个Python < - > C ++转换调用的开销,而不是典型的长度为N的数组所产生的N.
这个代码的稍微完整版本是我在github上的PyTRT项目的一部分。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.