我使用Boost python作为程序的计算密集型部分,并且它工作得很好,除了将数组从C ++传递到python而反之亦然非常慢,以至于它是整体效率的限制因素该计划。
这是一个说明我的观点的例子。在C ++方面,我返回一个类型为vector< vector<double> >
的矩阵,其大小相对较大。在python方面,我调用该函数并尝试使用两种不同的方法转换结果数组:numpy.array
方法,以及我自己的(可能非常天真)基本转换器的C ++实现。 C ++部分:
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace std;
typedef vector<double> vec;
typedef vector<vec> mat;
mat test()
{
int n = 1e4;
mat result(n, vec(n, 0.));
return result;
}
namespace p = boost::python;
namespace np = boost::python::numpy;
np::ndarray convert_to_numpy(mat const & input)
{
u_int n_rows = input.size();
u_int n_cols = input[0].size();
p::tuple shape = p::make_tuple(n_rows, n_cols);
np::dtype dtype = np::dtype::get_builtin<double>();
np::ndarray converted = np::zeros(shape, dtype);
for (u_int i = 0; i < n_rows; i++)
{
for (u_int j = 0; j < n_cols; j++)
{
converted[i][j] = input[i][j];
}
}
return converted;
}
BOOST_PYTHON_MODULE(hermite_cpp)
{
using namespace boost::python;
// Initialize numpy
Py_Initialize();
boost::python::numpy::initialize();
class_<vec>("double_vec")
.def(vector_indexing_suite<vec>())
;
class_<mat>("double_mat")
.def(vector_indexing_suite<mat>())
;
def("convert_to_numpy", convert_to_numpy);
def("test", test);
}
python部分:
import test
import numpy as np
import time
def timeit(function):
def wrapper(*args, **kwargs):
tb = time.time()
result = function(*args, **kwargs)
te = time.time()
print(te - tb)
return result
return wrapper
A = timeit(test.test)()
B = timeit(np.array)(A)
C = timeit(test.convert_to_numpy)(A)
该计划的结果如下:
0.56
36.68
26.56
转换能否更快?或者,更好的是,数组可以在numpy和C ++之间共享。我已经搜索了很长时间,但没有太大的成功。
答案 0 :(得分:2)
我一直以这种方式进行这些转换,而且表现非常快:
$subject = 'New message.';
$config = Array(
'protocol' => 'sendmail',
'smtp_host' => 'Your smtp host',
'smtp_port' => 465,
'smtp_user' => 'webmail',
'smtp_pass' => 'webmail pass',
'smtp_timeout' => '4',
'mailtype' => 'html',
'charset' => 'utf-8',
'wordwrap' => TRUE
);
$this->load->library('email', $config);
$this->email->set_newline("\r\n");
$this->email->set_header('MIME-Version', '1.0; charset=utf-8');
$this->email->set_header('Content-type', 'text/html');
$this->email->from('from mail address', 'Company name ');
$data = array(
'message'=> $this->input->post('message')
);
$this->email->to($toEmail);
$this->email->subject($subject);
$body = $this->load->view('email/sendmail.php',$data,TRUE);
$this->email->message($body);
$this->email->send();
然后在python:
void convert_to_numpy(const mat & input, p::object obj)
{
PyObject* pobj = obj.ptr();
Py_buffer pybuf;
PyObject_GetBuffer(pobj, &pybuf, PyBUF_SIMPLE);
void *buf = pybuf.buf;
double *p = (double*)buf;
Py_XDECREF(pobj);
u_int n_rows = input.size();
u_int n_cols = input[0].size();
for (u_int i = 0; i < n_rows; i++)
{
for (u_int j = 0; j < n_cols; j++)
{
p[i*n_cols+j] = input[i][j];
}
}
}
时序:
C = np.empty([10000*10000], dtype=np.float64)
timeit(test.convert_to_numpy)(A,C)
答案 1 :(得分:0)
这只是部分答案,因为我不完全理解它的工作原因,但我发现将转换功能重写为
np::ndarray convert_to_numpy(mat const & input)
{
u_int n_rows = input.size();
u_int n_cols = input[0].size();
p::tuple shape = p::make_tuple(n_rows, n_cols);
p::tuple stride = p::make_tuple(sizeof(double));
np::dtype dtype = np::dtype::get_builtin<double>();
p::object own;
np::ndarray converted = np::zeros(shape, dtype);
for (u_int i = 0; i < n_rows; i++)
{
shape = p::make_tuple(n_cols);
converted[i] = np::from_data(input[i].data(), dtype, shape, stride, own);
}
return converted;
}
显着提高了速度。
另一个解决方案是使用Boost::Multi_array
,以确保矩阵连续存储在内存中,从而产生更快的结果。
typedef boost::multi_array<double, 2> c_mat;
np::ndarray convert_to_numpy(c_mat const & input)
{
u_int n_rows = input.shape()[0];
u_int n_cols = input.shape()[1];
p::tuple shape = p::make_tuple(n_rows, n_cols);
p::tuple strides = p::make_tuple(input.strides()[0]*sizeof(double),
input.strides()[1]*sizeof(double));
np::dtype dtype = np::dtype::get_builtin<double>();
p::object own;
np::ndarray converted = np::from_data(input.data(), dtype, shape, strides, own);
return converted;
}
答案 2 :(得分:0)
我使用vector.data()作为源直接使用from_data调用
vector<double>vertices;
auto np_verts= np::from_data(vertices.data(), // data ->
np::dtype::get_builtin<double>(), // dtype -> double
p::make_tuple(vertices.size()), // shape -> size
p::make_tuple(sizeof(double)), p::object()); // stride 1