Cython基础教程(六) - Cython分析工具

当我们使用cython来加速python模块时,我们需要到底在什么地方需要写c/c++代码来进行来加速,在什么地方写python来保持代码的灵活性。

Cython运行时间分析

当我们优化cython代码的时候,首先需要知道什么地方的代码需要进行改变,可以使用内置的分析工具profile模块(更快的C执行,cProfile),来查看个行代码的运行时间。

当使用分析工具的时候不需要对pure-python代码进行任何改动,当python代码中调用了c/c++的库的时候,这些分析工具不能跨语言进行分析,所有在c-level的分析信息都丢失了。

Cython解决了这个问题,它生成的C代码和这些工具兼容,让这些工具认为c-level的调用都是常规的python调用.

为了说明如何使用分析工具,来看一个例子. 首先我们有一个pure-python的代码,intergrate.py

def integrate(a, b, f, N=2000):
    dx = (b-a)/N
    s = 0.0
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

再建立一个main.py来使用这个函数


from integrate import integrate
from math import pi, sin

def sin2(x):
    return sin(x)**2
    
def main():
    a, b = 0.0, 0.2*pi
    return integrate(a, b, sin2, N=400000)

# we use cProfile in profile our function, sorting by internal time spent in each function
if __name__ == '__main__':
    import cProfile
    cProfile.run('main()', sort='time')

本地运行代码
在这里插入图片描述
可以看到cProfile输出的结果。ncalls代表函数总条用次数,tottine列代表这个函数上总消耗的时间(不包含调用函数的时间),percall等于tottime除以ncalls. cumtime是这个函数上消耗的总时间(包含调用函数的时间),第二个percall等于cumtime除以ncalls。

接下来用静态类型声明来改进integrate函数。

def integrate(double a, double b, f, int N=2000):
    cdef:
        int i
        double dx = (b-a)/N
        double s = 0
    for i in range(N):
        s += f(a+i*dx)
    return s*dx

在这里插入图片描述
可以对上述代码进行编译,产生.so文件,然后在main函数中调用,用cProfile进行运行时间分析,可以看出性能有显著提高

结果分析

对于main.py中的sin2, 它是一个纯python函数,但是可以将它挪到integrate.pyx执行文件中,经过编译之后速度会更快

from math import sin

def sin2(x):
    return sin(x)**2
    
def integrate(double a, double b, f, int N=2000):
    cdef:
        int i
        double dx = (b-a)/N
        double s = 0
    for i in range(N):
        s += f(a+i*dx)
    return s*dx

在这里插入图片描述
结果分析

结果分析发现sin2函数需要很长的运行时间,那么有没有更快的方法呢?可以使用C标准苦衷额sin函数来进行加速, 只需要改进执行文件integrate.pyx中的import语句

from libc.math cimport sin

def sin2(x):
    return sin(x)**2
    
def integrate(double a, double b, f, int N=2000):
    cdef:
        int i
        double dx = (b-a)/N
        double s = 0
    for i in range(N):
        s += f(a+i*dx)
    return s*dx

**结果分析**

可以看到,性能又有进一步的提升

性能分析及注释

使用cProfile和Cython的profile运行时间分析工具可以直接告诉我们哪些代码运行时间很长,需要进行改进。但是为了理解为什么有些函数运行很慢,Cython提供了compile-time-annotations. 运行时间分析工具和编译注释为我们提供优化cython代码的一种方法。

对于编译注释,一个直观理解是如果一行Cython代码产生和很多调用python/c的API, 那么很有可能这行代码操作和很多python对象从而消耗了大量的时间。反之,如果一行cython代码只编译成比较短的C代码而且不调用C API, 那么这行代码会很快。

cython编译器有一个选项–annotate(short form: -a), 让cython生成一个HTML文件来表示Cython的源代码,一般叫做代码注释。如果一行代码有很多的C API调用,那么该行代码是深黄的,如果一行代码没有C API调用,那么该行代码没有高亮。

重新考虑integrate.pyx文件

def integrate(a, b, f, N=2000):
    dx = (b-a)/N
    s = 0.0
    for i in range(N):
        s += f(a+i*dx)
    return s * dx

可以用如下命令生成代码注释

$ cython --annotage integrate.pyx

可以打开看看生成的HTML文件。最后大家可以动手对integrate.pyx文件进行修改,用静态类型定义,然后重新生成代码注释,看看有什么变化。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值