![](/img/trans.png)
[英]Passing std:vector from C++ to Python via Ctypes: getting nonsensical values
[英]Improve speed of passing data from Python to C(++) via ctypes
对于时间要求严重的机器人应用程序,我需要优化循环中的函数调用。 我的脚本是在python中,它通过ctypes与我编写的C ++库接口,然后调用一个微控制器库。
瓶颈是向微控制器缓冲器添加位置 - 速度 - 时间点。 根据我的时序检查,通过ctypes调用C ++函数大约需要0.45
秒,而在C ++方面,调用函数需要0.17
秒。 我需要以某种方式减少这种差异。
这是相关的python代码,其中数据是一个点的2D数组,clibrary通过ctypes加载:
data_np = np.vstack([nodes, positions, velocities, times]).transpose().astype(np.long)
data = ((c_long * 4) * N)()
for i in range(N):
data[i] = (c_long * 4)(*data_np[i])
timer = time()
clibrary.addPvtAll(N, data)
print("clibrary.addPvtAll() call: %f" % (time() - timer))
这是被称为C ++的函数:
void addPvtAll(int N, long data[][4]) {
clock_t t0, t1;
t0 = clock();
for(int i = 0; i < N; i++) {
unsigned short node = (unsigned short)data[i][0];
long p = data[i][1];
long v = data[i][2];
unsigned char t = (unsigned char)data[i][3];
VCS_AddPvtValueToIpmBuffer(device(node), node, p, v, t, &errorCode);
}
t1 = clock();
printf("addPvtAll() call: %f \n", (double(t1 - t0) / CLOCKS_PER_SEC));
}
我并不一定非常需要使用ctypes,但我不想每次运行它时都要编译Python代码。
Python和C ++之间的往返可能很昂贵,尤其是在使用ctypes时 (类似于普通C / Python包装器的解释版本)。
您的目标应该是尽量减少旅行次数,并且每次旅行都能完成最多的工作。
它看起来像你的代码太精细的粒度(即做太多的旅行和每次旅行做太少的工作)。
numpy包可以将其数据直接暴露给C / C ++。 这样可以避免昂贵的装箱和拆箱的Python对象(带有随之而来的内存分配),它可以让你传递一系列数据点,而不是一次传递一个点。
修改您的C ++代码以一次处理多个点而不是每次调用一次(非常类似于sqlite3模块执行execute和executemany )。
这是我的解决方案,它有效地消除了Python和C之间测量的时间差。感谢kirbyfan64sos建议SWIG和Raymond Hettinger用于C-arrays的numpy。 我在Python中使用了一个numpy数组,它纯粹作为一个指针发送给C - 在两种语言中都访问相同的内存块。
C函数保持相同,除了使用gettimeofday()
而不是clock()
,这给出了不准确的时间:
void addPvtFrame(int pvt[6][4]) {
timeval start,stop,result;
gettimeofday(&start, NULL);
for(int i = 0; i < 6; i++) {
unsigned short node = (unsigned short)pvt[i][0];
long p = (long)pvt[i][1];
long v = (long)pvt[i][2];
unsigned char t = (unsigned char)pvt[i][3];
VCS_AddPvtValueToIpmBuffer(device(node), node, p, v, t, &errorCode);
}
gettimeofday(&stop, NULL);
timersub(&start,&stop,&result);
printf("Add PVT time in C code: %fs\n", -(result.tv_sec + result.tv_usec/1000000.0));
}
另外,我安装了SWIG并在我的interfaces文件中包含以下内容:
%include "numpy.i"
%init %{
import_array();
%}
%apply ( int INPLACE_ARRAY2[ANY][ANY] ) {(int pvt[6][4])}
最后,我的Python代码通过numpy将pvt
构造为一个连续的数组:
pvt = np.vstack([nodes, positions, velocities, times])
pvt = np.ascontiguousarray(pvt.transpose().astype(int))
timer = time()
xjus.addPvtFrame(pvt)
print("Add PVT time to C code: %fs" % (time() - timer))
测量的时间现在在我的机器上有大约1%的差异。
你可以使用data_np.data.tobytes()
:
data_np = np.vstack([nodes, positions, velocities, times]).transpose().astype(np.long)
timer = time()
clibrary.addPvtAll(N, data_np.data.tobytes())
print("clibrary.addPvtAll() call: %f" % (time() - timer))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.