-
说明
尝试翻译Cython Documentation以助学习。
水平有限,乐迎指正;文档首页:《Cython官方文档中文翻译》
-
通过静态类型加速代码
Cython
是一个Python编译器
。这意味着它可以无损编译普通Python代码
(除去有少许尚不支持的语言特性,详见Cython limitations)。然而,对于关键性能代码,增加静态类型声明
是一种常见的有效方式,因为他们使Cython
脱离Python
代码的动态特性,并生成更简单、更快的C代码
–有时会快几个数量级。类型声明会造成源代码冗余,也就降低了可读性。因此不建议在非必须情况下使用,例如基准测试证明他们确实在性能关键部分显著提速。通常情况下,正确位置的几种类型非常有效。
可声明所有
C类型
:整型(integer)
、浮点型(floating point)
、复数(complex numbers)
、structs
、unions
、pointer
。Cython
可以在分配的类型之间自动且正确的转换。也包括Python
任意大小的整型(integer)
,如果在转换成C代码
过程中出现溢出错误会在Python
报OverflowError
错误(但是,在进行算术运算时,并不会检查溢出错误)。在这种情况下,生成的C代码会安全正确的处理好与平台相适应的C类型
大小。类型,是通过cdef关键字声明的。
-
定型变量
考虑下述纯Python代码:
def f(x): return x ** 2 - x def integrate_f(a,b,N): s = 0 dx = (b - a) / N for i in range(N): s += f(a + i * dx) return s * dx
仅需用
Cython
编译,就可提速35%。这总比没有好,然是增加一些静态类型会带来更大改变。随着额外声明类型,代码如下:
def f(double x): return x ** 2 -x def integrate_f(double a, double b, int N): cdef int i cdef double s, dx s = 0 dx = (b - a) / N for i in range(N): s += f(a + i * dx) return s * dx
由于迭代器变量i是用
C语言
定型的,此处for循环会被编译成纯C代码
。指定a,s,dx
类型非常重要,因为他们涉及for循环中的算术运算,对b,N
的定型相对就不那么重要了,不过在本例中一致的定型整个函数并不会增加额外工作量。加速效果:相比于纯
Python
有四倍提速。 -
定型函数
Python
函数调用功耗很大,在Cython
中更是翻倍(in Cython doubly
),因为需要在Python
对象之间进行反复转换。在上节例子中,在f()及调用f()时其参数都假设时C double类型,然而还是需要构造一个Python float对象已备传入。因此,
Cython
提供了一种声明C风格
的语法,即cdef
关键字:cdef double f(double x) except? -2: return x ** 2 - x
通常应添加某种形式的
except-modifier
,否则Cython无法传播该函数(或其调用的函数)中出现的异常。except?-2
意思是,如果返回-2
,就检查错误(尽管?
表明-2
也可以作为一个有效的返回值)或者,慢一点的
except *
总是安全的。如果返回一个
Python对象
或保证函数内调用不出错,异常子句(except clause)可以忽略(left out)。cdef的一个副作用是函数在
Python
空间就无效了,因为Python
不知道如何调用它。运行过程中也不能更改f()。相比于cdef,cpdef关键字会同时创建一个
Python
封装器,因此函数在Cython
(快速,直接传入定型的值)和Python
(在Python
对象中封装值)中同时有效。事实上,cpdef不仅提供了一个Python
封装器,还安装了逻辑,即便是在cython内调用时方法还可被python方法覆盖。与cdef方法相比,这确实增加了一点点开销。加速效果:
150
倍于纯Python
-
确定添加类型的位置
因为静态类型添加常常是提速关键,初学者倾向于定型所有内容。这就导致可读性、灵活性双降,甚至会导致降速(比如,添加不必要的类型检查、转换‘缓慢的缓冲区拆包)。另一方面,如果忘记定型一个关键循环变量就会大大拉低表现。针对此问题的两大利器是profiling、annotation:
profiling
,应是任何优化行为的第一步,可以告诉你哪里(where)拖了速度的后退;- Cython’s
annotation
,则会告诉你代码为何(why)耗时;
采用
-a
转到cython
命令行程序(Sage notebook
择时跟随link
),进入Cython
代码与生成的C代码
相互交错存在的HTML
报告。行(lines)根据“typedness”着色:- white lines,转成
纯C
; - yellow lines,需要
Python C-API
(需要更多C-API
交互,则颜色更深);
转成
C代码
的行前面有个“+”
,并可点开查看生成的代码。当优化函数提速,及确定何时
发布GIL
( release the GIL)时,此报告非常重要:通常,nogil块
可能只有“white”代码。Cython
会根据变量的指配推定局部变量的类型(包括作为循环变量目标),这也可以在任何地方减少显示指定类型的需要。例如,上例中声明dx为double是不必要的,最后版本的s类型也是(f的返回值类型是C double)。有个例外,计算算术表达式中的整型(integer
),由于Cython
无法保证不出现溢出(因此如果需要Python
的bignum
,则可返回object
)。如要允许推定C整型
,可将inter_types指令(directive )设置为True。此指令功能类似于C++的auto关键字。减少定型
所有的需求可能很有用,也可能因此导致意外,特别是对于不熟悉C类型写算术表达式的人。详细的快速教程参见链接。 -
References
Cython官方文档中文翻译:通过静态类型加速代码
最新推荐文章于 2023-03-04 03:50:57 发布