Fom*_*aut 5 python gcc ctypes i2c raspberry-pi
我试图找出为什么当我尝试写入 I2C 时,即使我使用 CDLL,Python 中的相同代码的工作速度也比 C 慢 25 倍。下面我将逐步描述我正在做的所有细节。
树莓派版本:Raspberry PI 3 Model B
操作系统:Raspbian Buster Lite 版本:2019 年 7 月
GCC 版本:gcc (Raspbian 8.3.0-6+rpi1) 8.3.0
Python 版本:Python 3.7.3
尽管 I2C,我正在使用的设备是 MCP23017。我所做的就是将 0 和 1 写入引脚 B0。这是我用 C 编写的代码:
// test1.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <time.h>
int init() {
int fd = open("/dev/i2c-1", O_RDWR);
ioctl(fd, I2C_SLAVE, 0x20);
return fd;
}
void deinit(int fd) {
close(fd);
}
void makewrite(int fd, int v) {
char buffer[2] = { 0x13, 0x00 };
buffer[1] = v;
write(fd, buffer, 2);
}
void mytest() {
clock_t tb, te;
int n = 1000;
int fd = init();
tb = clock();
int v = 1;
for (int i = 0; i < n; i++) {
makewrite(fd, v);
v = 1 - v;
}
te = clock();
printf("Time: %.3lf ms\n", (double)(te - tb) / n / CLOCKS_PER_SEC * 1e3);
deinit(fd);
}
int main() {
mytest();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我使用以下命令编译并运行它:
gcc test1.c -o test1 && ./test1
Run Code Online (Sandbox Code Playgroud)
它给了我结果:
pi@raspberrypi:~/dev/i2c_example $ gcc test1.c -o test1 && ./test1
Time: 0.020 ms
Run Code Online (Sandbox Code Playgroud)
我可以得出结论,写入引脚需要 0.02 毫秒。
之后,我创建 SO 文件以便能够从我的 Python 脚本访问编写的函数:
gcc -c -fPIC test1.c -o test1.o && gcc test1.o -shared -o test1.so
Run Code Online (Sandbox Code Playgroud)
还有我要测试的 Python 脚本:
# test1.py
import ctypes
from time import time
test1so = ctypes.CDLL("/home/pi/dev/i2c_example/test1.so")
test1so.mytest()
n = 1000
fd = test1so.init()
tb = time()
v = 1
for _ in range(n):
test1so.makewrite(fd, v)
v = 1 - v
te = time()
print("Time: {:.3f} ms".format((te - tb) / n * 1e3))
test1so.deinit(fd)
Run Code Online (Sandbox Code Playgroud)
这为我提供了结果:
pi@raspberrypi:~/dev/i2c_example $ python test1.py
Time: 0.021 ms
Time: 0.516 ms
Run Code Online (Sandbox Code Playgroud)
我不明白为什么makewrite在 Python 中调用25 倍,尽管实际上我调用了相同的 C 代码。我也研究了,如果我的评论write(fd, buffer, 2);中test1.c或更改fd到1,由Python脚本给出的时间是兼容的,有没有这样的巨大差异。
// in test1.c
write(fd, buffer, 2); -> write(1, buffer, 2);
Run Code Online (Sandbox Code Playgroud)
运行 C 程序:
pi@raspberrypi:~/dev/i2c_example $ gcc test1.c -o test1 && ./test1
...Time: 0.012 ms
Run Code Online (Sandbox Code Playgroud)
运行 Python 程序:
pi@raspberrypi:~/dev/i2c_example $ python3 test1.py
...Time: 0.009 ms
...Time: 0.021 ms
Run Code Online (Sandbox Code Playgroud)
这让我很困惑。谁能告诉我为什么会发生这种情况,以及如何使用 C-DLL 通过 I2C 提高我在 Python 中的性能?
概括:
描述符:1(标准输出)
纯 C 语言 makewrite 的执行时间:0.009 ms
从 Python 调用 C-DLL 函数的 C 中 makewrite 的执行时间:0.021 毫秒
结果可想而知。这个差别并没有那么大。可以解释为,Python 循环及其语句不如 C 中的高效,因此增加了执行时间。
描述符:I2C
纯 C 语言 makewrite 的执行时间:0.021 ms
从 Python 调用作为 DLL 函数的 C 中 makewrite 的执行时间:0.516 ms
文件描述符切换到I2C纯C周围增加了执行时间后0.012 ms,所以我期望的执行时间从Python的呼唤:0.021 ms + 0.012 ms = 0.033 ms,因为所有的改变我已经做在里面的makewrite,所以Python应该不知道这个内部东西(因为它打包在 so-file 中)。但我有,0.516 ms而不是0.033 ms让我感到困惑。