提高通过 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代码。
和 C++ 之间的往返可能很昂贵,尤其是在使用 ctypes 时(这类似于普通 C/Python 包装器的解释版本(。
您的目标应该是尽量减少行程次数,并在每次行程中尽可能多地完成工作。
在我看来,您的代码粒度太细(即每次旅行都做太多而做的工作太少(。
numpy 包可以直接向 C/C++ 公开其数据。 这将让你避免昂贵的Python对象装箱和拆箱(以及随之而来的内存分配(,并且它将允许你传递一系列数据点,而不是一次传递一个点。
修改C++代码以一次处理多个点,而不是每次调用一次(就像 sqlite3 模块对执行与执行所做的那样(。
这是我的解决方案,它有效地消除了Python和C之间的测量时间差。 感谢kirbyfan64sos建议SWIG和Raymond Hettinger在numpy中用于C数组。我在 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: %fsn", -(result.tv_sec + result.tv_usec/1000000.0));
}
此外,我安装了 SWIG 并在我的接口文件中包含以下内容:
%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))
- Ctypes wstring通过引用传递
- 为什么在读取文件大小时文件IO速度会发生变化
- 在C++代码中包含opencv时,使用ctypes创建.so文件
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- 文件系统:复制功能的速度秘诀是什么
- 学习多线程C++:添加线程不会使执行速度更快,即使它看起来应该
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- Python ctypes:不会按预期加载 dll
- 将 ctypes 与 tesserac-ocr 一起使用的例外 TessPageIteratorBoundingBox.
- 在C++中使用并行化的预期速度是多少(不是 OpenMp,而是 <thread>)
- 两个连续的 OpenMP 并行区域会相互减慢速度
- 如何使用 ctypes 停止和重新启动从 Python 运行的C++代码
- 查找标准::hash_map与标准::矢量的速度
- 加快在C++中读取/处理日志文件的速度
- 为什么这些算法的运行速度比它们应该的要快?
- 如何提高文件的读取速度?
- 通过libpqxx提高PostgreSQL数据库的更新速度
- 使用 IMFSinkWriter 编码的视频的播放速度会根据宽度而变化
- 计算车辆之间的距离并设置速度,使距离保持不变,例如 5 米
- 提高通过 ctypes 将数据从 Python 传递到 C(++) 的速度