繁体   English   中英

提高通过ctypes将数据从Python传递到C(++)的速度

[英]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模块执行executeexecutemany )。

这是我的解决方案,它有效地消除了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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM