背景

Python作为最方便的编程语言和丰富的配置而被大家推崇。 但是当我们的模型较复杂,运算量较大的时候,python的短板就会出现,执行速度并不那么理想,加上GIL的限制,让Python开发人员大为担忧,如何摆脱Python的这个短板而又不摒弃使用Python的快感呢?答案就是使用Cython。使用Cython,你可以避开Python的许多原生限制,或者完全超越Python,而无需放弃Python的简便性和便捷性。
Cython出现就是让Python也可以被编译,然后执行。大家要区别Cpython和Cython,Cpython大家可以认为是python的一种,其实大家平时使用的基本都是cpython。而Cython大家可以直接理解为一种语言,Cython是一种部分包含和改变C语言,以及完全包含pyhton语言的一个语言集合。
Cython可以在Python中掺杂C和C++的静态类型,cython编译器可以把Cython源码编译成C或C++代码,编译后的代码可以单独执行或者作为Python中的模型使用。Cython中的强大之处在于可以把Python和C结合起来,它使得看起来像Python语言的Cython代码有着和C相似的运行速度。

1. Cython 的简介和安装
Cython 是让 Python 脚本支持 C 语言扩展的编译器,Cython 能够将 Python + C 混合编码的 .pyx 脚本转换为 C 代码,主要用于优化Python脚本性能或Python调用C函数库。由于Python固有的性能差的问题,用C扩展Python成为提高Python性能常用方法,Cython 算是较为常见的一种扩展方式。
安装 Cython 的方法也是非常简单 直接使用 pip 工具即可直接在线安装。如下图:

Windows 和 Linux 下安装过程一样,这里展示一下在 Windows 下的安装命令(途中显示我已经安装过,版本号是 0.27.3)。后续的章节中实例实在虚拟机虚拟的 Ubuntu18.04 的 64 位的操作系统上运行的。运行的实际效果和各自的电脑有密切关系。

2. 将纯 Python 程序转换后的运行效率对比
首先编写一个测试程序来测试运行消耗的时长,这里实现了两个功能,一个是计算圆周率的功能,一个是函数的递归调用。具体实现代码如下:

# coding=utf-8
import mathdef pi(n):s = 0.0 for i in range(n+1):s+= 1.0/(2*i+1)/(2*i+1)return math.sqrt(8*s)def flb(n):if n == 0:return 0if n == 1:return 1return flb(n-1)+flb(n-2)

这两个功能一目了然,保存为 compute.py。
下面看一下测试这两个功能的测试程序 test.py,代码如下:

# coding=utf-8
import compute
import timestart_time = time.clock()
ret = compute.pi(20000000)
print(ret)
end_time = time.clock()
print ("pi time: %f s" % (end_time - start_time))start_time = time.clock()
ret = compute.flb(40)
print(ret)
end_time = time.clock()
print ("flb time: %f s" % (end_time - start_time))

运行一下就知道这两个功能所消耗的时间了,结果如下:

计算圆周率循环 20000000 次花费时间 2.7s 左右。递归调用 40 次的时间是 29s 多。

下面我们将 compute.py 复制成 compute.pyx
然后编写一个 setup.py 的文件,如下:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonizesetup(name = 'compute',ext_modules=cythonize([Extension("compute", ["compute.pyx"]),]),
)

再编写一个 Makefile 文件 ,如下:

all:python3 setup.py build_ext --inplaceclean:@echo Cleaning compute@rm -f compute.c *.o *.so@rm -rf build

三个文件放在同一个目录下,然后运行 make 命令即可编译出一个 .so 的文件(当然你也可以不使用 Makefile 直接使用 python3 setup.py build_ext --inplace 也是可以的),如下图:

注意: 在 Windows 下生成的是一个 .pyd 的文件, Linux 下生成的是 .so 文件,这些文件可以直接被 Python 调用的。
同样运行 test.py 文件,效果如下:

从结果看,效果还是挺明显的,计算圆周率从 2.7 秒 到了 1.9 秒。递归调用从 29 秒到了 6 秒。不要骄傲,下面我们继续,还有提升的空间。

3. Cython 和 Python 混合编程的效率
上面仅仅是将原生的 Python 程序用 Cython 编译了一下效率就提高了不少。下面我们继续。
将上面那个 compute.pyx 文件稍作修改,如下:

# coding=utf-8
import math
cpdef double pi(int n):cdef double s = 0.0 for i in range(n+1):s+= 1.0/(2*i+1)/(2*i+1)return math.sqrt(8*s)cpdef int flb( int n):if n == 0:return 0if n == 1:return 1return flb(n-1)+flb(n-2)

然后重新编译,然后运行 test.py ,效果如下:

通过对比可发现,计算圆周率的并没有很大的优化,但是 递归调用的那个所用的时间已经不到半秒钟了,从最初的 29 秒到现在的 0.36秒 可以说是一个非常棒的优化了。

4. 引入 C 库后的运行效率
从上面我们可以发现,计算圆周率的时候使用了 Python 的数学库 math ,现在我们使用 C 语言的 math.h 库试一试。将 compute.pyx 文件稍作修改,如下:

# coding=utf-8
cdef extern from "math.h":double sqrt(double theta)cpdef double pi(int n):cdef double s = 0.0 for i in range(n+1):s+= 1.0/(2*i+1)/(2*i+1)return sqrt(8*s)
cpdef int flb( int n):if n == 0:return 0if n == 1:return 1return flb(n-1)+flb(n-2)

然后使用 Makefile 编译一下,然后运行 test.py ,效果如下:

效果并没有太大改进嘛。也就可以说明在这个程度上 Python 中的数学库的 sqrt 和 C 语言的 sqrt 运行效率相当。下面我们继续优化之旅。
5. 自定义 C 语言编译成 Python 模块
如果我们完全使用 C 语言实现这两个功能运算效果会如何呢? 首先我们使用 C 语言实现这两个功能,代码如下( fun.c ):

#include "stdio.h"
#include "math.h"
static double pi_fun(int n){double s = 0.0;for (int i = 0; i < n+1; ++i){s += 1.0/(2*i+1)/(2*i+1);}return sqrt(8*s);
}static int flb_fun(int n){if (n == 0){return 0;}if (n == 1){return 1;}return flb_fun(n-1)+flb_fun(n-2);
}

将 compute.pyx 做如下修改:

# coding=utf-8
cdef extern from "fun.c":double pi_fun(int n)int flb_fun(int n)cpdef double pi(int n):return pi_fun(n)cpdef int flb( int n):return flb_fun(n)

然后编译,运行 test.py ,效果如下:

这个结果还是挺喜人的,20000000 次的循环计算圆周率从先前的 2.7 秒到现在的 0.05 秒, 40 次的递归调用耗时从先前的 29 秒 优化到 0.36 秒;

所有源码都已经上传 GitHub (https://github.com/EricLmy/demo.git) 可以自行下载。

6. 如何巧妙的避开局限
Cython也是有局限的,毕竟Cython不是万能的。它不会自动将每一个 Python 代码变成极速的 C 代码。为了充分利用Cython,你必须明智地使用它,并理解它的局限性:

  1. 常规 Python 代码的加速很少
  2. 原生 Python 数据结构有一点加速
  3. Cython 代码运行速度最快的时候就是全部使用 C 实现

这里只是提供Cython这一种优化效率的方法,当然还有很多其他的方法,这里就不多说了,另外还有一个将 C 编译成库文件( dll 文件)的方法,具体请查看我的微信公众号
(搜索微信公众号:离梦远)

Cython使用技巧相关推荐

  1. python基础===Python 代码优化常见技巧

    Python 代码优化常见技巧 代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优化.扩展以及文档相关的事情通常需要消耗 8 ...

  2. Python 常见优化技巧,让你的程序溜溜的跑起来!

    代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优化.扩展以及文档相关的事情通常需要消耗 80% 的工作量.优化通常包含两方 ...

  3. just函数python_提升 Python 性能 Numba 与 Cython

    ? "Python猫" ,一个值得加星标的公众号花下猫语:最近,读者微信群里又频繁聊到了 Python 的性能问题,这真是老生常谈了.我想起自己曾收藏过几篇关于如何提升性能的文章, ...

  4. python中if的效率_Python 代码性能优化技巧

    选择了脚本语言就要忍受其速度,这句话在某种程度上说明了 python 作为脚本的一个不足之处,那就是执行效率和性能不够理想,特别是在 performance 较差的机器上,因此有必要进行一定的代码优化 ...

  5. python linux 优化_Python 代码性能优化技巧

    Python 性能优化除了改进算法,选用合适的数据结构之外,还有几种关键的技术,比如将关键 python 代码部分重写成 C 扩展模块,或者选用在性能上更为优化的解释器等,这些在本文中统称为优化工具. ...

  6. pandas object转float_25个Pandas实用技巧

    本文一共为大家分享25个pandas技巧,此为上篇~显示已安装的版本 输入下面的命令查询pandas版本: In [7]:pd.__version__Out[7]:'0.24.2' 如果你还想知道pa ...

  7. Jupyter Notebook数据科学高效技巧

    摘要: 本文有一些关于Jupyter Notebook的干货,希望看完文章可以给你带来收获 当我学习有关深度学习的优秀的fast.ai课程时,我学到了很多适用于通用软件工程的干货.我写这篇文章是为了总 ...

  8. Python 代码优化常见技巧

    代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优化.扩展以及文档相关的事情通常需要消耗 80% 的工作量.优化通常包含两方 ...

  9. python求圆柱体的体积_Python 常见优化技巧,让你的程序溜溜的跑起来!

    点击上方  编程学习者社区,选择  创建星标 回复关键字资源获取编程资料 代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优 ...

  10. python代码性能优化技巧

    python代码性能优化技巧 代码优化能够让程序运行更快,可以提高程序的执行效率等,对于一名软件开发人员来说,如何优化代码,从哪里入手进行优化?这些都是他们十分关心的问题.本文着重讲了如何优化Pyth ...

最新文章

  1. redis java客户端配置,Java的Redis客户端选择-jedis与Lettuce
  2. php强制对齐,[强迫症福利] 使用 PHPStorm 对齐数组的键值对
  3. AGC027B Garbage Collector
  4. 从源码分析RocketMQ系列-消息拉取PullMessageProcessor详解
  5. CCF201803-2 碰撞的小球
  6. 【Spring】Spring Bean 生命周期
  7. Java static , final和常量设计
  8. php mysql异常捕获_PHP中try{}catch{}的用法及异常处理.对数据库的事物支持
  9. Cookie/Session机制具体解释
  10. 打包的时候不把配置文件加进去_苹果软件打包签名原理
  11. Atitit 提升语法级别4gl 4.5g 4.9g 5g 目录 1. 语言级别表 1 2. 4.9g实现细节 2 2.1. $dollor前导符 2 2.2. Static变量 2 2.3. S
  12. 开启 Kerberos 安全的大数据环境中,Yarn Container 启动失败导致作业失败
  13. 第五章 7-1 输出星期名缩写
  14. java文件流写入文件_JAVA 输入输出流 本地文件读写
  15. ping通www.baidu.com的完整过程。
  16. 《Python编程 从入门到实践》简单读书笔记
  17. android入门视频教程!Android开发者跳槽面试,已拿offer入职
  18. linux基础知识(持续更新)
  19. C练题笔记之:Leetcode-1455. 检查单词是否为句中其他单词的前缀
  20. 【扔掉计算器】数学心算法《超棒超快》

热门文章

  1. 电脑插入耳机后没反应怎么办?
  2. matlab解决力学问题程序,力学专业程序实践:用MATLAB解决力学问题的方法与实例...
  3. RouterOS 重置密码
  4. html甘特图制作,AnyGantt实例教程——在Web网页中快速创建甘特图
  5. 深度学习方法的超分辨率(Super-resolution)方向论文【不定期更新】
  6. 实验数据处理的基本方法
  7. 1024程序员节日背后的神秘面纱
  8. Win10_ltsc_2019_x64集成DPO基于人工智能优化可动态提高应用程序性能提升高达394%
  9. ipsec ikev2 中转
  10. pdf转图片怎么清晰?