Disclaimer:本文的对象为对Python比较熟悉的用户。对一些基础的Python概念将不做介绍。
本文的算法并不一定最优,主要目的是为了展示Cython的一些基本概念
本文不需要精通C或C++,但是知道基本的指针,类型和内存概念会有帮助。
我在之前几篇文章中提到过作为数据科学家的一项技能是编写高性能的机器学习,脚本和其他程序。然而大多数情况下我们都希望只使用一种语言环境,而Python基本是默认的DS编程环境。那么如果有需要极大压榨程序性能的话,就可以利用Cython。这篇文章并不会触及细节的内容,只是让读者自行确认是否有学习cython的必要。后续文章将通过一些例子来介绍一些常用的方法。
什么是Cython?
Cython并不是C,也不是Python,他是一个将介于C和Python之间的语言结构编译成C,然后在Python中运行的接口。它保持了大多数Python的语法结构,支持所有Python的命令,并通过一定方法加入C的结构,从而绕过Python的重重转译和类型检查,来实现快速的程序。
大多数Python整合包都会包括Cython。你也可以通过pip来安装:
pip install Cython
与Python不一样,你并不能直接使用Cython的源代码。需要通过编译来完成从Python调用C程序的目的。此外,没有错,如果你有用C直接编写的程序,可以用Cython来调用纯C程序!
Cython同样支持C++
Cython自带一些C和C++的标准库
ipython支持直接在命令行编译和使用cython程序!然而我的实践发现可能出现奇怪bug。
Cython的参考书非常少,最常用的一本是Cython A GUIDE FOR PYTHON PROGRAMMERS。然而……此书非常不详尽,绝对不是noob friendly…… 建议有什么问题还是stackoverflow求助大牛。
什么时候用Cython?
切记:Cython并不是所有python速度问题的良药。它牺牲了flexibility来换取速度,你必须要考虑所有细节问题,包括很多python新手甚至老手忽略了的、Python帮你暗地里处理好的问题。如果你需要大量使用python的类,请慎重考虑是否使用。
如果并没有大量循环,或者最内层的循环有一些复杂python的类,请慎重使用。
如果不需要重复使用脚本,请慎重使用。
如果提升只有不到20%,请慎重使用。
如果这个函数或者类会被很多人debug和改进,请慎重使用。除非很多人熟悉Cython,不然maintain程序会非常麻烦。
如果不能确定性能瓶颈是你要改写为cython的函数,请慎重使用。
如果你不会从200%的速度提升中获得快感,请慎重使用。
学习Cython前的思考:
你是否滥用了Python的灵活性?
如果你经常编写类似下面的函数,你可能需要在学习cython之前改变你的习惯:
def foo(arg):
if isinstance(arg, str):
# Do something
elif isinstance(arg, str):
# Do something
else:
# Do something
有一个确定input类型的函数非常有用。Python没有像C++和java那种overload的保护,很容易引起麻烦。
if foo == "astring":
foo = myClass()
这本身就不是很好的python编写习惯,除非重新赋值为不同类型变量会节省巨大内存使用,不然这种用法及其容易引起混淆。
你是否因为调用函数而没有思考复杂度?
请参考附录文章1. 连续使用一些内置函数确实可以实现提速作用,但是有可能进行了多余的运算。在进行Cython编写的时候需要在除去Python冗余检查的前提下(例如,请记住,在Cython中使用循环没有任何问题,甚至可能是进行细微调整的优化的前提),尽可能地实现运算次数的最小化。
你是否对基本数据结构有所了解?
这里的数据结构并不是数据科学意义上的数据库结构,而是基本的整数,浮点等。使用Cython的一个重要的技巧就是尽量利用和改写输入数据的组成方式:保证统一形式,确认是某种类型,确认长度,等等。
减少字符串操作。字符串操作是python的长处,如果你需要处理大量的字符串集,请考虑是否可以先创建一个dictionary来进行string -> int/long的对应。
能保证有整齐的数据为佳。list of list,如果知道每个字列都是同样长度,转化为齐整的array更好。
如有兴趣请继续看 :Weiwen Gu:用Cython来提高Python代码速度 [二]zhuanlan.zhihu.com
附录