Cython是一个快速生成Python扩展模块的工具,从语法层面上来讲是Python语法和C语言语法的混血,当Python性能遇到瓶颈时,Cython直接将C的原生速度植入Python程序,这样使Python程序无需使用C重写,能快速整合原有的Python程序,这样使得开发效率和执行效率都有很大的提高,而这些中间的部分,都是Cython帮我们做了,接下来简单说一下Cython的安装和使用方法

一、首先Cython官网地址是:http://cython.org/ 这里有cython的安装和开发文档,关于Cython的下载可以在pypi上直接下载安装包:https://pypi.python.org/pypi/Cython/ 由于是在Linux下安装使用,这里下载的是Cython-0.25.2.tar.gz,上传至linux执行如下步骤安装:

tar -xvzf Cython-0.25.2.tar.gz

cd Cython-0.25.2python setup.pyinstall

这样Cython模块就安装成功了

然后我们首先看一下cython的基本使用,首先 mkdir hello_pack && cd hello_pack 建立一个目录并且进入,然后编写一个hello.pyx的脚本,代码如下:

#coding=utf-8

defprint_hello(name):print "Hello %s!" % name

代码很简单,就是一个函数,然后编写一个setup.py,代码如下:

from distutils.core importsetupfrom distutils.extension importExtensionfrom Cython.Distutils importbuild_ext

ext_modules= [Extension("hello",["hello.pyx"])]

setup(

name= "Hello pyx",

cmdclass= {'build_ext': build_ext},

ext_modules=ext_modules

)

这里导入了Cython的模块,其中setup name指定模块的名称,然后执行编译命令:

python setup.py build_ext --inplace

编译完之后,看到当前目录下会生成两个文件,一个是hello.c一个是hello.so,hello.c就是转换而成的c代码,而hello.so就是我们需要的python经过Cython编译之后的模块,我们为了当前目录可被调用,建立__init__.py内容如下:

#coding=utf-8

from hello import *

然后执行 cd .. 回到上层目录,建立一个hello.py,代码如下:

#!/usr/bin/python

# coding=utf-8from hello_pack import hello

hello.print_hello("cython")

很简单,就是调用我们编译好的hello模块,然后执行里面的方法,现在直接执行hello.py,看到输出结果正常

那么现在,我们就完成了Cython的基本使用,其实setup.py编译脚本也可以写成如下这样:

from distutils.core importsetupfrom Cython.Build importcythonize

setup(

name='Hello pyx',

ext_modules=cythonize('hello.pyx')

)

这种写法更通用,编译的时候直接使用 python setup.py build 就可以了,注意不是install,执行install后会把模块复制到python系统目录下了;

执行完之后,会看到当前目录有一个build目录,然后进去会发现有如下两个目录:

第二个temp是编译过程中汇编生成的.o文件,第一个lib开头的目录中存放的就是hello.so文件,直接把这个文件拷贝出来就可以使用了,另外为了方便,运行脚本直接和so文件放在一个目录下就可以,直接使用import hello即可导入,也不用建立__init__.py了

二、以上就是基本的Cython使用,下面借助一个案例来说明Cython和Python程序有哪些性能方面的提升

首先我们编写一个compute.py,封装了两个计算的方法,代码如下:

#coding=utf-8

importmathdefspherical_distance(lon1, lat1, lon2, lat2):

radius= 3956x= math.pi/180.0a= (90.0 - lat1)*x

b= (90.0 - lat2)*x

theta= (lon2 - lon1)*x

distance= math.acos(math.cos(a)*math.cos(b)) + (math.sin(a) * math.sin(b) *math.cos(theta))return radius *distancedeff_compute(a, x, N):

s=0

dx= (x - a)/Nfor i inrange(N):

s+= ((a + i * dx) ** 2 - (a + i *dx))return s * dx

第一个方法可以计算地球表面任意两个经纬度之间的距离,这个方法使用了很多三角函数,这些三角函数由python的math模块提供;第二个方法就是纯数字的计算

那么现在编写一个执行脚本来调用函数,test.py代码如下:

#!/usr/bin/env python#coding=utf-8

importcomputeimporttime

lon1, lat1, lon2, lat2= -72.345, 34.323, -61.823, 54.826start_time=time.clock()

compute.f_compute(3.2, 6.9, 1000000)

end_time=time.clock()print "runing1 time: %f s" % (end_time -start_time)

start_time=time.clock()for i in range(1000000):

compute.spherical_distance(lon1, lat1, lon2, lat2)

end_time=time.clock()print "runing2 time: %f s" % (end_time - start_time)

代码就是分别执行100000次数字计算和距离计算,并打印之间,执行结果如下:

可以看到数字计算耗时0.33s,距离计算耗时1.34s,然后我们尝试直接用Cython模块进行编译

首先复制出来一份 cp compute.py compute1.pyx 然后编写setup1.py

from distutils.core importsetupfrom Cython.Build importcythonize

setup(

name='compute_module',

ext_modules=cythonize('compute1.pyx'),

)

写完之后直接执行 python setup1.py build 编译,编译完之后导入compute1.so这个模块,现在只需要修改头部import compute为import compute1 as compute这样能保证下面调用代码不变,然后执行,结果如下:

现在会发现时间比刚才快了一点,说明性能有所提升,然后继续进行优化,这次全部变量都使用静态类型,即变量类型提前定义,compute2.pyx代码如下:

#coding=utf-8

importmath

cpdef float spherical_distance(float lon1, float lat1, float lon2, float lat2):

cdef float radius= 3956cdef float pi= 3.14159265cdef float x= pi/180.0cdef float a,b,theta,distance

a= (90.0 - lat1)*x

b= (90.0 - lat2)*x

theta= (lon2 - lon1)*x

distance= math.acos(math.cos(a)*math.cos(b)) + (math.sin(a) * math.sin(b) *math.cos(theta))return radius *distancedeff_compute(double a, double x, int N):

cdef int i

cdef double s=0

cdef double dx= (x - a)/Nfor i inrange(N):

s+= ((a + i * dx) ** 2 - (a + i *dx))return s * dx

现在可以看到类型全部做了定义,在cython里面,类型定义使用cdef float这种方式进行;对于方法来说,如果模块内部相互调用那么同样使用cdef double这种的方式来定义,如果这个方法要在我们外部执行脚本中调用,那么要么是python原生方法不做任何修改,要么写成cpdef float这种类型的形式,方法定义类型可以提高效率,但是提高不大,但是变量静态类型可以极大的提高效率,原因是参与计算的主要是变量;假如一个函数被频繁调用,那么有必要使用cdef或者cpdef来定义;现在同样方法编译compute2模块,然后在test.py中调用,执行结果如下:

现在发现纯数字计算的时间几乎变成了0秒!而第二个用了0.81s,比刚才快了,但是似乎并不是很快,原因仔细想想会发现,这里面调用了很多三角函数,使用的还是python内置的math模块,这里可以用C语言的math.h来代替,所以再写一个compute3.pyx如下:

#coding=utf-8#import math

cdef extern from "math.h":

float cosf(float theta)

float sinf(float theta)

float acosf(float theta)defspherical_distance(float lon1, float lat1, float lon2, float lat2):

cdef float radius= 3956cdef float pi= 3.14159265cdef float x= pi/180.0cdef float a,b,theta,distance

a= (90.0 - lat1)*x

b= (90.0 - lat2)*x

theta= (lon2 - lon1)*x

distance= acosf(cosf(a)*cosf(b)) + (sinf(a) * sinf(b) *cosf(theta))return radius *distancedeff_compute(double a, double x, int N):

cdef int i

cdef double s=0

cdef double dx= (x - a)/Nfor i inrange(N):

s+= ((a + i * dx) ** 2 - (a + i *dx))return s * dx

这次我们屏蔽了自身的math模块,然后调用了C的头文件math.h,并引入了cosf,sinf,acosf,实际上这三个函数返回的都是float类型,和我们定义的一致,如果我们想使用double类型,那么应该直接使用cos,sin,acos函数,并且我们可以对这些函数再包装,这样cpdef就派上用场了,比如下面:

cdef extern from "math.h":

double cos(double)

double sin(double)

cpdef double tangent(double x):return sin(x)/cos(x)

比如这里定义了一个测试的tangent正切函数,就是上面这样写;同样我们现在编译compute3.pyx并测试,结果如下:

现在第一个仍然是接近于0s完成,而第二个三角函数换成C的之后,性能有的非常大的提升,可以说几乎接近于原生C语言的效率了,这样看来从Python到Cython性能得到了很大的优化,但是代码量确差别没有用C重写那么大

根据上面的案例,我们知道在数字,浮点数等计算中Cython可以极大的提高性能,而这方面多线程几乎不能提高任何性能,有时候反而会降低;但是对于io密集型的场合,用Cython基本上也没有性能上太大的提升,而多线程的将拥有更加出色的性能,所以Cython应该专注与计算方面的优化;总结一下也就是对于IO密集型应用,优化可以考虑使用多线程或者多进程方式,对于计算密集型的场合,遇到瓶颈时可以考虑使用Cython或者封装C相关的模块

最后,虽然Cython非常好用,但也不能疯狂的使用,推荐一句名言:我们应该忘记小的效率,过早的优化是一切罪恶的根源,有 97% 的案例如此。简单来说就是选择恰当的时机进行优化

python转cython_Cython的简单使用相关推荐

  1. 使用Python,OpenCV实现简单的场景边界/拍摄转换检测器

    使用Python,OpenCV进行简单的场景边界/拍摄转换检测器 1. 效果图 2. 实现 2.1 步骤 2.2 什么是"场景边界"和"拍摄过渡"? 2.3 代 ...

  2. python tkinter库、添加gui界面_使用Python中tkinter库简单gui界面制作及打包成exe的操作方法(二)...

    使用Python中tkinter库简单gui界面制作及打包成exe的操作方法(二),创建一个,界面,布局,文件,路径 使用Python中tkinter库简单gui界面制作及打包成exe的操作方法(二) ...

  3. python m http_非常简单的Python HTTP服务

    如果因为某种需求急需一个web服务器,而又不至于去在httpd和nginx中配置一个新的虚拟主机,Python或许可以帮上这个临时的小需求. 使用Python可以完成一个简单的内建 HTTP 服务器. ...

  4. python的变量和简单的数据类型

    决定学习python这门语言了,本人资质愚钝,只会把学到的东西记录下来,供自己查漏补缺,也可以分享给和我一样正在学习python语言的人,若在记录中存在什么错误,希望多多批评指正,谢谢. Python ...

  5. 怎么进入python官网-Python的安装及简单的使用

    原标题:Python的安装及简单的使用 像我们想要抓住一门好的编程语言,如何开始学习呢?我来简单介绍下python Python特性:语法简单,入门上手快,很多女神也在学习,方便找个编程的妹纸---- ...

  6. php和python哪个学起来简单一点-作为初学者,php,python和ruby应学哪个?

    [IT168 评论]对于web开发初学者来说,最大的问题就是学习哪种编程语言更适合未来的职业发展并且更有前景.你要考虑都有哪些编程语言,各自的优缺点是什么.每种编程语言的学习周期有多长等问题.互联网上 ...

  7. 大学python和vb哪个简单-python和vb哪个简单

    Visual Basic(简称VB)是Microsoft公司开发的一种通用的基于对象的程序设计语言,为结构化的.模块化的.面向对象的.包含协助开发环境的事件驱动为机制的可视化程序设计语言.是一种可用于 ...

  8. python和vb的代码可以通用吗-python和vb哪个简单

    Visual Basic(简称VB)是Microsoft公司开发的一种通用的基于对象的程序设计语言,为结构化的.模块化的.面向对象的.包含协助开发环境的事件驱动为机制的可视化程序设计语言.是一种可用于 ...

  9. python的简单编程-python入门脚本的简单示例

    编程之家收集整理的这篇文章主要介绍了python入门脚本的简单示例,编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考. 感兴趣的小伙伴,下面一起跟随编程之家 jb51.cc的小编来看看吧. ...

  10. php和python哪个学起来简单一点-python和php哪个容易学

    python和PHP的难易程度并没有明确的界限,如果是零基础的小白,建议学php会好一些,原因大公司小公司创业公司非互联网公司,都会用到php,python都是大公司在用 或互联网公司在用以你目前的背 ...

最新文章

  1. Springboot 中的header, cookie, session
  2. Power BI统一报表平台演示环境发布
  3. SPOOLing技术的再思考
  4. 4月10日服务器例行维护公告,4月12日服务器例行维护公告(已完成)
  5. 【VHDL语言学习笔记(七)】 分频器
  6. 【Visual c++ Build Tools】下载
  7. java吸_结对编程(java)
  8. 萝卜青菜各有所爱------htm 与 html
  9. 关于结构光问题的总结
  10. 怎么把视频变成GIF
  11. 月老在线牵盲盒/交友盲盒/一元交友/存取小纸条盲盒/分销功能
  12. 中联医疗系统服务器,中联医学影像系统(PACS)
  13. 现代操作系统学习笔记三、死锁
  14. 【PAT甲级】1021 Deepest Root (25 分)(暴力,DFS)
  15. web前端利用jq实现选项卡切换功能
  16. JNI开发基础知识及编译SO(一)
  17. STM32生态系统 第三期(一)STM32WB无线协议栈和用户应用升级的准备工作
  18. 华为服务器怎么查看cpu型号,华为RH2288H V2处理器性能测试_华为 FusionServer RH2288 V2_服务器评测与技术-中关村在线...
  19. ANSYS Workbench结构动力学专题视频教程
  20. 99%的老板都不知道的股权设计

热门文章

  1. DBCC--SHOWCONTIG
  2. Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(3)...
  3. poj 2329 Nearest number - 2 这道题广搜为什么就是wa啊!!求解
  4. 苹果Mac Win10式任务栏工具:uBar
  5. 从这6个方面,帮你轻松管理Chrome中保存的密码!
  6. 第三次作业N的阶乘以及第四次一维数组实现杨辉三角
  7. 改变Linux的DNS解析顺序(DNS到hosts)
  8. Linux网络服务_dhcp服务和dhcp中继服务
  9. EF BB BF的问题
  10. servlet执行流程代码分析