查看原文
其他

Cython 是什么编程语言?为什么你有必要学习一下

南风草木香 Python开发者 2022-07-28

【导语】:这篇文章主要介绍了Cython编程语言,它是Python语言的超集,简而言之:Cython就是具有 C 数据类型的 Python。通过把Cython编译为C语言,运行程序。不仅保留了Python开发方便的特点,还能提升代码的运行速度,非常值得学习。

介绍

Python语言因使用方便、第三方库丰富,得到了许多开发者的青睐。但是Python的缺点也很明显,就是运行速度较慢。为了解决这个问题,Cython出现了,Cython也是一种编程语言,可以把它理解为Python的超集,简而言之:Cython就是具有 C 数据类型的 Python。通过把Cython编译为C语言,可以提升代码的性能。对于使用Python原生对象的代码,效果可能并不明显。但是对于其他没有使用Python对象的代码,或者数值运算等操作而言,效果很不错。

通过使用Cython,我们不仅可以继续利用Python开发快速的特点,又可以让代码运行速度像C语言一样快。本文我们将介绍Cython的更多细节,同时还将简单使用下它。

1. 将Python编译为C语言

在Python中,我们可以直接调用C语言库,包括通用的C库和Python专用的库。在Cython中,我们还能调用使用了Python语法的C语言库。

从语法上看,Cython与Python很相似。如果我们用Cython编译器运行一个Python文件(Python 2.x 和 Python 3.x均可),虽然可以正常运行,但是运行速度与使用Python解释器没有区别。假如我们使用Cython中的类型声明语法来修改Python代码,最终编译时就可以把运行速度较慢的Python对象替换为等效的C语言代码。

注意Cython的使用可以是渐进式的,这意味着开发者要想使用Cython优化原来的Python应用程序,不用刚开始就重写所有代码,只需要更改局部代码就可以。Cython之所以这样设计,是因为在大多数程序中,只有部分代码造成了程序运行慢 - 这可以用帕累托法则解释,也就是“二八准则”。因此Python程序中80%的代码都不用优化,只需对少数关键代码进行优化。我们可以把关键代码用Cython重写,提升性能。其余代码继续使用Python语法,保证代码的简洁性。

2. 简单使用Cython

我们来看看下面这个例子:

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

这段代码封装了一个求积分的函数,由于是纯Python写的,需要在本机数值类型和Python内部对象之间来回转换,速度会比较慢。我们使用Cython对以上代码进行重构:

cdef double f(double x):
    return x**2-x

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

如果我们对函数形参、函数体中的变量都声明变量类型(double, int等),Cython会把这些代码都编译为C语言。为了提高运行速度,我们还可以用cdef关键字来定义主要用C语言实现的函数,但之后只能用Cython函数来调用这些函数。上面的代码中,只有integrate_f函数可以被Python调用,因为它是使用def关键字定义的,而cdef定义的函数没有Python接口。

可以发现,我们只是在原来的代码中添加了类型声明,并没有修改多少代码,但是运行速度会得到极大提升。

3. Cython NumPy

由于Cython代码能编译成C语言,因此可以直接与第三方数据处理库交互,例如Numpy,从而提升程序性能。在Cython中,我们可以快速访问Numpy数组。此外,我们之前在Python中操作Numpy的语法在Cython中,仍然可以使用。

但是如果你想将Cython与Numpy绑定起来,则需要用Cython的语法修改代码。例如,你可以使用cimport在代码编译时查看库中的C代码结构。如果你已经安装了NumPy,可以在代码中使用cimport numPy导入Numpy。

Cython的优点

除了能提升代码性能,Cython还具有以下优点:

1. 使用第三方C语言库速度更快

NumPy等Python包,将C语言库封装在了Python接口中,使得调用更加方便。然而,在Python和C之间来回切换会影响代码的运行速度。Cython可以直接调用C语言库(还支持c++库),省去了来回切换花费的时间。

2. 可以同时使用C和Python进行内存管理

如果在代码中用到了Python对象,你可以用Python语言中的方法进行内存管理和垃圾回收。也可以使用malloc/free来对C数据结构进行内存管理,但是最后要手动清除。

3. 更安全

Cython通过装饰器和编译器指令(例如@boundscheck(False)),来自动检查C代码运行时的问题,例如越界访问数组就会报错。因此,在默认情况下,Cython生成的C代码要比手写的C代码安全得多,尽管可能速度会慢一些。

如果你想提升运行速度,就可以禁用自动检查功能,针对整个模块或者具体函数都可以。Cython还可以直接访问内存中的Python数据。

4. 释放GIL以提升性能

Python的全局解释器锁(Global Interpreter Lock,简称GIL),它的主要功能是:在解释器中执行的每一个线程,都会先锁住自己,以阻止别的线程执行。但是许多开发者都认为GIL影响了Python程序的性能,尤其是在多核系统上。

如果你的Python程序中有一段代码没有使用Python对象,可以考虑使用with nogil,来释放GIL。这样在这段代码执行期间,解释器就可以运行其他线程的代码了。

5. Cython可以使用Python类型提示语法

Python有一种类型提示语法,主要用于对代码进行检查。Cython中有可用于代码修饰的自定义语法,但在Cython的最新版本中,你也可以使用Python类型提示语法。这种模式被称为“纯python模式”。我在另一篇文章中介绍了如何使用“纯python模式”[1]

Cython的限制

Cython无法将一个漏洞百出的Python代码转换为性能优越的C代码。我们必须了解清楚Cython的局限性:

1. 对Python的原生数据结构作用不太明显

Python语法有许多数据结构:字符串、列表、元组、字典等,使用起来很方便,并且自带内存管理机制。但相比纯C语言,速度要慢很多。我们可以使用C语言的变量和数据结构,来提升性能。

2. 当使用“纯C代码”时,Cython代码运行最快

如果你在Cython中,用cdef关键字定义了一个纯C语言编写的函数,那么它的运行速度将与C一样快。但是如果该函数调用了Python代码,那么就会影响性能。

幸运的是,在Cython中我们可以通过源代码报告发现上述问题,该报告会直观地显示哪部分是纯C,哪部分与Python交互。一般而言,与Python的交互就越少,性能就越好。

下图是一个Cython程序的源代码报告。白色区域是纯C代码,黄色区域表示与Python交互的代码。一个性能优越的Cython程序中黄色部分比较少。

源代码报告

分析Cython的性能

Cython自带性能检测工具,例如cProfile[2],我们可以使用该工具分析代码性能。

Cython也不是万能的,它并不能保证一定可以提高代码运行速度。通常情况下,Python代码和Cpython代码的交互越少,程序的性能越好。例如,如果你需要在Cython中处理一组对象,那么不要在Python中遍历它,然后每一步都去调用一个Cython函数。正确的做法是将整个集合传递给Cython模块,在Cython中进行处理。这一技巧在管理数据库时可以使用。

我们使用Python是因为它语法简洁,开发效率高,但是Python程序的运行速度比较慢。通过使用Cython,可以有效地提升程序运行速度。

参考资料

[1]

“纯python模式”: https://www.infoworld.com/article/3648539/faster-python-made-easier-with-cythons-pure-python-mode.html

[2]

cProfile: https://www.infoworld.com/article/3329750/how-to-profile-python-code.html

[3]

参考原文: https://www.infoworld.com/article/3250299/what-is-cython-python-at-the-speed-of-c.html

- EOF -


加主页君微信,不仅Python技能+1

主页君日常还会在个人微信分享Python相关工具资源精选技术文章,不定期分享一些有意思的活动岗位内推以及如何用技术做业余项目

加个微信,打开一扇窗



推荐阅读  点击标题可跳转

1、很期待!尝鲜 Python 3.11 的 5 个新特性

2、这个字典库引起了 Python 之父的注意!你用过吗?

3、抓取速度提升 3 倍!Python 的这个内置库你用上了吗?


觉得本文对你有帮助?请分享给更多人

推荐关注「Python开发者」,提升Python技能

点赞和在看就是最大的支持❤️

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存