Python便于开发但是效率一般,C/C++效率较高但是开发难度相对更大,这可以说是老生常谈了。对于我这样的业余人士而言,效率并不是那么重要,但是如果能够做相对少的工作,而使得性能可以有较大的改善,我当然还是乐意的。这里介绍一下我对ctypes调用dll的简单测试。

首先,编写一个C的程序。这里使用最简单的累加来测试速度。

1
2
3
4
5
6
/* test.c */
void sumup();

void sumup() {
for(unsigned long long i = 1; i <= 1000000; i++) {}
}

然后,使用gcc将test.c编译为Python可以调用的dll(注意是否添加了环境变量)。

1
gcc test.c -shared -fPIC -o test.dll

在Python中分别通过ctypes调用sumup累加和使用Python实现累加,并通过装饰器(鸣谢:@Toyomu)计时。由于单次运行时间较短,为方便起见,这里选择了在Python中循环调用来延长时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from ctypes import *
from time import time

fw = open('data.dat', 'w') # 记录数据用于分析
dll = CDLL(r'.\test.dll') # 加载dll

# 使用装饰器重复调用,计时输出并记录
def deco(order):
def wrapper(func):
def _deco():
t1 = time()
for i in range(50):
func()
t2 = time() - t1
print('Time cost of {}: {}'.format(func.__name__, t2))
fw.write('{:.5f},'.format(t2)) if order == 1 else fw.write('{:.5f}\n'.format(t2))
return _deco
return wrapper

@deco(order = 1)
def c():
dll.sumup()

@deco(order = 2)
def py():
for i in range(1000000):
pass

# 生成多组数据
for i in range(80):
c()
py()

fw.close()

结束后,在data.dat中可见用时数据记录。

data.dat

这里已经显然可以看到运行速度的巨大差异。我们在SPSS中使用配对样本t-test来进一步验证。

data.dat

可见,p < 0.001,结果非常显著。

作为业余人士,这样的结果还是很让我惊喜的。调用过程并不复杂,而性能的差异也是十分明显的,这也是预料之中的。C/C++的强大自不必说,但Python的体验更佳这一点也是自然的,所以对我来说,以Python为主体,而在制约性能的模块上部分采用C/C++重写是很好的策略。当然,这似乎也是实际开发中的常态了。