作者:perrygeo

译者:赖勇浩(http://laiyonghao.com)

原文:http://www.perrygeo.net/wordpress/?p=116

我最喜欢的是Python,它的代码优雅而实用,可惜纯粹从速度上来看它比大多数语言都要慢。大多数人也认为的速度和易于使用是两极对立的——编写C代码的确非常痛苦。而 Cython 试图消除这种两重性,并让你同时拥有 Python 的语法和 C 数据类型和函数——它们两个都是世界上最好的。请记住,我绝不是我在这方面的专家,这是我的第一次Cython真实体验的笔记:

编辑:根据一些我收到的反馈,大家似乎有点混淆——Cython是用来生成 C 扩展到而不是独立的程序的。所有的加速都是针对一个已经存在的 Python 应用的一个函数进行的。没有使用 C 或 Lisp 重写整个应用程序,也没有手写C扩展 。只是用一个简单的方法来整合C的速度和C数据类型到 Python 函数中去。

现在可以说,我们能使下文的 great_circle 函数更快。所谓 great_circle 是计算沿地球表面两点之间的距离的问题:

p1.py

import math

def great_circle(lon1,lat1,lon2,lat2):

radius = 3956 #miles

x = math.pi/180.0

a = (90.0-lat1)*(x)

b = (90.0-lat2)*(x)

theta = (lon2-lon1)*(x)

c = math.acos((math.cos(a)*math.cos(b)) +

(math.sin(a)*math.sin(b)*math.cos(theta)))

return radius*c

让我们调用它 50 万次并测定它的时间 :

import timeit

lon1, lat1, lon2, lat2 = -72.345, 34.323, -61.823, 54.826

num = 500000

t = timeit.Timer("p1.great_circle(%f,%f,%f,%f)" % (lon1,lat1,lon2,lat2),

"import p1")

print "Pure python function", t.timeit(num), "sec"

约2.2秒 。它太慢了!

让我们试着快速地用Cython改写它,然后看看是否有差别:

c1.pyx

import math

def great_circle(float lon1,float lat1,float lon2,float lat2):

cdef float radius = 3956.0

cdef float pi = 3.14159265

cdef float x = pi/180.0

cdef float a,b,theta,c

a = (90.0-lat1)*(x)

b = (90.0-lat2)*(x)

theta = (lon2-lon1)*(x)

c = math.acos((math.cos(a)*math.cos(b)) + (math.sin(a)*math.sin(b)*math.cos(theta)))

return radius*c

请注意,我们仍然import math——cython让您在一定程度上混搭Python和C数据类型在。转换是自动的,但并非没有代价。在这个例子中我们所做的就是定义一个Python函数,声明它的输入参数是浮点数类型,并为所有变量声明类型为C浮点数据类型。计算部分它仍然使用了Python的 math 模块。

现在我们需要将其转换为C代码再编译为Python扩展。完成这一部的最好的办法是编写一个名为setup.py发布脚本。但是,现在我们用手工方式 ,以了解其中的巫术:

# this will create a c1.c file - the C source code to build a python extension

cython c1.pyx

# Compile the object file

gcc -c -fPIC -I/usr/include/python2.5/ c1.c

# Link it into a shared library

gcc -shared c1.o -o c1.so

现在你应该有一个c1.so(或.dll)文件,它可以被Python import。现在运行一下:

t = timeit.Timer("c1.great_circle(%f,%f,%f,%f)" % (lon1,lat1,lon2,lat2),

"import c1")

print "Cython function (still using python math)", t.timeit(num), "s

约1.8秒 。并没有我们一开始期望的那种大大的性能提升。使用 python 的 match 模块应该是瓶颈。现在让我们使用C标准库替代之:

c2.pyx

cdef extern from "math.h":

float cosf(float theta)

float sinf(float theta)

float acosf(float theta)

def great_circle(float lon1,float lat1,float lon2,float lat2):

cdef float radius = 3956.0

cdef float pi = 3.14159265

cdef float x = pi/180.0

cdef float a,b,theta,c

a = (90.0-lat1)*(x)

b = (90.0-lat2)*(x)

theta = (lon2-lon1)*(x)

c = acosf((cosf(a)*cosf(b)) + (sinf(a)*sinf(b)*cosf(theta)))

return radius*cec"

与 import math 相应,我们使用cdef extern 的方式使用从指定头文件声明函数(在此就是使用C标准库的math.h)。我们替代了代价高昂的的Python函数,然后建立新的共享库,并重新测试:

t = timeit.Timer("c2.great_circle(%f,%f,%f,%f)" % (lon1,lat1,lon2,lat2),

"import c2")

print "Cython function (using trig function from math.h)", t.timeit(num), "sec"

现在有点喜欢它了吧?0.4秒 -比纯Python函数有5倍的速度增长。我们还有什么方法可以再提高速度?c2.great_circle()仍是一个Python函数调用,这意味着它产生Python的API的开销(构建参数元组等),如果我们可以写一个纯粹的C函数的话,我们也许能够加快速度。

c3.pyx

cdef extern from "math.h":

float cosf(float theta)

float sinf(float theta)

float acosf(float theta)

cdef float _great_circle(float lon1,float lat1,float lon2,float lat2):

cdef float radius = 3956.0

cdef float pi = 3.14159265

cdef float x = pi/180.0

cdef float a,b,theta,c

a = (90.0-lat1)*(x)

b = (90.0-lat2)*(x)

theta = (lon2-lon1)*(x)

c = acosf((cosf(a)*cosf(b)) + (sinf(a)*sinf(b)*cosf(theta)))

return radius*c

def great_circle(float lon1,float lat1,float lon2,float lat2,int num):

cdef int i

cdef float x

for i from 0 < = i < num:

x = _great_circle(lon1,lat1,lon2,lat2)

return x

请注意,我们仍然有一个Python函数( def ),它接受一个额外的参数 num。这个函数里的循环使用for i from 0 < = i < num: ,而不是更Pythonic,但慢得多的for i in range(num):。真正的计算工作是在C函数(cdef)中进行的,它返回float类型。这个版本只要0.2秒——比原先的Python函数速度提高10倍。

为了证明我们所做的已经足够优化,可以用纯C写一个小应用,然后测定时间:

#include

#include

#define NUM 500000

float great_circle(float lon1, float lat1, float lon2, float lat2){

float radius = 3956.0;

float pi = 3.14159265;

float x = pi/180.0;

float a,b,theta,c;

a = (90.0-lat1)*(x);

b = (90.0-lat2)*(x);

theta = (lon2-lon1)*(x);

c = acos((cos(a)*cos(b)) + (sin(a)*sin(b)*cos(theta)));

return radius*c;

}

int main() {

int i;

float x;

for (i=0; i < = NUM; i++)

x = great_circle(-72.345, 34.323, -61.823, 54.826);

printf("%f", x);

}

用gcc -lm -o ctest ctest.c编译它,测试用time ./ctest ...大约0.2秒 。这使我有信心,我Cython扩展相对于我的C代码也极有效率(这并不是说我的C编程能力很弱)。

能够用 cython 优化多少性能通常取决于有多少循环,数字运算和Python函数调用,这些都会让程序变慢。已经有一些人报告说在某些案例上 100 至 1000 倍的速度提升。至于其他的任务,可能不会那么有用。在疯狂地用 Cython 重写 Python 代码之前,记住这一点:

"我们应该忘记小的效率,过早的优化是一切罪恶的根源,有 97% 的案例如此。"——Donald Knuth

换句话说,先用 Python 编写程序,然后看它是否能够满足需要。大多数情况下,它的性能已经足够好了……但有时候真的觉得慢了,那就使用分析器找到瓶颈函数,然后用cython重写,很快就能够得到更高的性能。

外部链接

WorldMill(http://trac.gispython.org/projects/PCL/wiki/WorldMill)——由Sean Gillies 用 Cython 编写的一个快速的,提供简洁的 python 接口的模块,封装了用以处理矢量地理空间数据的 libgdal 库。

编写更快的 Pyrex 代码(http://www.sagemath.org:9001/WritingFastPyrexCode)——Pyrex,是 Cython 的前身,它们有类似的目标和语法。

本文标题: Cython 三分钟入门教程

本文地址: http://www.cppcns.com/jiaoben/python/51428.html

python 三分钟入门_Cython 三分钟入门教程相关推荐

  1. 五分钟教你使用vue-cli3创建项目(三种创建方式,小白入门必看)

    五分钟教你使用vue-cli3创建项目(三种创建方式,小白入门必看) 一.搭建vue环境 安装Nodejs 官网下载Nodejs,如果希望稳定的开发环境则下LTS(Long Time Support) ...

  2. 快速入门:十分钟学会Python

    初试牛刀 假设你希望学习Python这门语言,却苦于找不到一个简短而全面的入门教程.那么本教程将花费十分钟的时间带你走入Python的大门.本文的内容介于教程(Toturial)和速查手册(Cheat ...

  3. python 嵌套数组_兴趣是最好的老师,快速入门:十分钟学会python

    初试牛刀 假设你希望学习Python这门语言,却苦于找不到一个简短而全面的入门教程.那么本教程将花费十分钟的时间带你走入Python的大门.本文的内容介于教程(Toturial)和速查手册(Cheat ...

  4. python高阶函数(三分钟读懂)

    python高阶函数(三分钟读懂) 函数式编程 Python中,函数是一等对象 一等对象:具有特点 ① 对象是在运行时创建的 ② 能赋值给变量或作为数据结构中的元素 ③ 能作为参数传递 ④ 能作为返回 ...

  5. python三本经典书籍-《python编程入门经典》python之父推荐这三本书让你更快入门...

    在学习python的时候,我们不得不看一些书籍来辅助.有哪些书籍是比较经典的呢?python之父给大家推荐这3本书,其中又2本是属于一个系列,即<Python核心编程>第二版和第三版,一本 ...

  6. python快速入门【三】-----For 循环、While 循环

    python入门合集: python快速入门[一]-----基础语法 python快速入门[二]----常见的数据结构 python快速入门[三]-----For 循环.While 循环 python ...

  7. Python入门(三)--- 元组,字典,集合

    Python入门(三) 文章目录 Python入门(三) @[toc] 回顾 1 基本数据类型 2 判断条件 3 数学运算 4 字符串 5 列表 6 循环 元组的取值 元组的方法 元组的相对不可变 f ...

  8. 三步即可完成的OCR入门 | Python版

    点击关注我哦 一篇文章带你了解三步即可完成的OCR入门 在<这篇文章>中,我们有简单提到"Optical Character Recognition(OCR)"的相关内 ...

  9. 小猪的Python学习之旅 —— 10.三分钟上手Requests库

    小猪的Python学习之旅 -- 10.三分钟上手Requests库 标签:Python 一句话概括本文: 本节讲解Requests库的常见使用,以及一个实战项目: 扒取某一篇微信文章里所有的图片,视 ...

最新文章

  1. 程序化广告(4):考核指标
  2. 全球首个 AI 说唱歌手 TikTok 发新歌,虚拟偶像正当时
  3. linux xampp常见问题
  4. JZOJ 4910. 【NOIP2017模拟12.3】子串
  5. 大数据打造你的变美频道——数加平台上小红唇的大数据实践
  6. js使用深度优先遍历实现getElmentById(id)
  7. CSS 加过渡效果transition
  8. ActiveRecord 模式杂谈
  9. android 安装卸载应用提醒_Android程序使用代码的安装和卸载!!!
  10. 编译Android VNC Server(pc远程控制android)
  11. python部署到服务器上解析不到模块_在服务器上部署kafka-python包
  12. 服务器系统在虚拟机安装win7系统安装教程,虚拟机安装教程图解 虚拟机安装win7步骤...
  13. PorterLB使用手册
  14. 计算机家庭网络共享,教大家家庭局域网如何共享
  15. 大学操作系统期末考试复习经典计算题快速回顾
  16. oracle篮球,篮球小王子!任嘉伦打篮球也不来赖,超爱11号
  17. jquery 获取父级元素、子级元素、兄弟元素的方法
  18. AJAX()请求参数
  19. C++ conversion operator
  20. C语言小程序——数的重组

热门文章

  1. Udacity机器人软件工程师课程笔记(四)-样本搜索和找回-基于漫游者号模拟器-决策树
  2. Python中使用中文正则表达式匹配指定的中文字符串
  3. Ubuntu 14.04 64bit上编译安装simple-rtmp-server(srs)服务器
  4. 最全19000+国外AE模板合集包
  5. 如何用 ndctl/ipmctl 管理工具 配置不同访问模式的pmem设备
  6. ubuntu18.04.1内核升级至5.0.0-25版本
  7. 06 面向对象之:反射,双下方法
  8. Mac OS Terminal Commands
  9. GDC2016 Epic Games【Bullet Train】 新风格的VR-FPS的制作方法
  10. 《c陷阱与缺陷》之贪心法