Cython入门(一)计算斐波那契数列

本文将会通过一个简单的例子来作为Cython系列的入门文章。

Cython介绍

Cython的本质可以总结为:Cython是具有C数据类型的Python。

Cython就是Python:几乎所有的Python代码都是有效的Cython代码。(有少量例外,但这里我们先承认这个结论。)Cython的编译器会把代码转换成等效于调用Python/C API的C代码。

但是Cython远不止于此,因为它的参数和变量可以被声明为具有C数据类型。我们可以自由地混用操作Python值和C值的代码,而Cython会帮助我们自动转换需要转换的地方。Python中的引用计数保存和错误检查也是自动的,而且Python的异常处理机制,包括try-except和try-finally同样可行——即使是在操作C数据时。

总的来说,Cython 可以让我们方便地:

  • 用 Python 的语法混合编写 Python 和 C/C++ 代码,提升 Python 速度
  • 调用 C/C++ 代码

下面我们将会通过一个简单的计算斐波那契数列的例子来了解Cython的使用方式。

一个简单的例子:计算斐波那契数列

  • 原始的python代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding: utf-8 -*-
# @file: fibonacci.py
def cal_fibonacci(n: int) -> int:
if n <= 1:
return 1
else:
return cal_fibonacci(n-1) + cal_fibonacci(n-2)


if __name__ == '__main__':
import time
s_time = time.time()
result = cal_fibonacci(n=35)
print(result, (time.time() - s_time) * 1000)
  • pyx文件
1
2
3
4
5
6
7
8
9
10
# -*- coding: utf-8 -*-

cdef int _calc_fibonacci_number_c(int n):
if n <= 1:
return n
else:
return _calc_fibonacci_number_c(n-1) + _calc_fibonacci_number_c(n-2)

def calc_fibonacci_number_c(n):
return _calc_fibonacci_number_c(n)

可以看到,pyx文件的写法中加入了C语言的数据类型,这就是Cython的程序代码了,看上去与Python十分相似,这无疑是很方便学习的。

注意: cdef定义的_calc_fibonacci_number_c函数,我们将无法通过Python的模块调用方式来调用,因此,我们又实用了def来定义Python中的calc_fibonacci_number_c函数。

  • 编译文件: setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
# setup.py
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(ext_modules = cythonize(Extension(
'c_fibonacci',
sources=['c_fibonacci.pyx'],
language='c',
include_dirs=[],
library_dirs=[],
libraries=[],
extra_compile_args=[],
extra_link_args=[]
)))
  • 编译

运行命令:

1
python setup.py build_ext --inplace

--inplace可用-i代替。

编译完后会生成同名的以.c和.so文件为后缀的文件。(Linux系统为so文件,Windows为pyd文件)

  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
# -*- coding: utf-8 -*-
import time
from fibonacci import cal_fibonacci_number
import c_fibonacci

n = 35
s_time = time.time()
result1 = cal_fibonacci_number(n)
e1_time = time.time()
print(result1, (e1_time - s_time) * 1000)
result2 = c_fibonacci.calc_fibonacci_number_c(n)
e2_time = time.time()
print(result1, (e2_time - e1_time) * 1000)

运行结果:

1
2
14930352 3129.063129425049
14930352 52.85525321960449

在笔者的Windows电脑上运行,Cython的运行时间比Python快大约60倍,这无疑是让人惊讶的。

参考文献

  1. Cython 基本用法: https://zhuanlan.zhihu.com/p/24311879
  2. HatBoy's Github Pages': https://hatboy.github.io/page/4/
  3. OReilly.Cython-A-Guide-for-Python-Programmers.pdf: http://www.jyguagua.com/wp-content/uploads/2017/03/OReilly.Cython-A-Guide-for-Python-Programmers.pdf

欢迎关注我的公众号NLP奇幻之旅,原创技术文章第一时间推送。

欢迎关注我的知识星球“自然语言处理奇幻之旅”,笔者正在努力构建自己的技术社区。


Cython入门(一)计算斐波那契数列
https://percent4.github.io/Cython入门(一)计算斐波那契数列/
作者
Jclian91
发布于
2024年5月3日
许可协议