上一节中,IntegralOccupancyMap()
函数用来确定单词位置,其中调用了query_integral_image()
方法。而query_integral_image
是用来Cython。下边介绍Cython。
Cython介绍
Cython 的本质可以总结如下:Cython 是包含C 数据类型的Python。
Cython可以将Python代码编译成动态链接库,在某些情况下,可以极大提高Python程序的运行效率。
可以看到源码中包括了query_integral_image.pyx
和query_integral_image.c
两个文件。其中.c
文件是Cython自动生产的对应query_integral_image.pyx
C语言程序。
Cython的工作流程大致如下:
我们只需要关心.pyx
文件中的代码
为了测试使用Cython是否真的可以提高程序效率,我们做如下测试,
系统:Ubuntu 16
环境:python3.5
依赖:
Cython==0.28.2
numpy==1.14.2
Pillow==5.1.0
测试代码均可从github下载
测试过程
目录tree
.
├── python_query_integral_image.py
├── query_integral_image.pyx
├── setup.py
├── test.py
└── venv
setup.py用来编译动态链接库,内容如下:
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("query_integral_image.pyx")
)
执行:
python setup.py build_ext --inplace
然后目录变为了:
.
├── build
├── python_query_integral_image.py
├── query_integral_image.c
├── query_integral_image.cpython-35m-i386-linux-gnu.so
├── query_integral_image.pyx
├── setup.py
├── test.py
└── venv
下边我们就可以在python程序中import编译后的.so
文件了,
测试程序test.py如下:
# 导入python编写的程序,为了和.so区别,改名为python_query_integral_image
from python_query_integral_image import query_integral_image as q1
# 导入经过Cython处理的.so链接库
from query_integral_image import query_integral_image as q2
from random import Random
import numpy as np
import timeit
DX = 3000
DY = 3000 # 相当于一个3000*3000=900万像素的图片
integral = np.zeros((DX, DY), dtype=np.uint32)
random_state = Random()
start_time = timeit.default_timer()
q1(integral, 50, 50, random_state)
end_time = timeit.default_timer()
q1_dur = (end_time - start_time)/60.
start_time = timeit.default_timer()
q2(integral, 50, 50, random_state)
end_time = timeit.default_timer()
q2_dur = (end_time - start_time)/60.
print('C程序耗时', q2_dur, 'Python耗时', q1_dur)
print('相差%f倍' % (float(q1_dur) / float(q2_dur)))
运行测试程序,结果令人吃惊:
C程序耗时 0.0007940871333024309 Python耗时 0.6854850105833369
相差863.236516倍
经过Cython简单的处理,同样的代码,运行效率提高了800多倍。刺不刺激?
可见在作矩阵计算或者循环次数较多时,Cython具有较大作用。