Cython入门.VS.C++
原文链接:http://blog.csdn.net/gzlaiyonghao/article/details/4561611
作者:perrygeo
译者:赖勇浩(http://laiyonghao.com)
我最喜欢的是Python,它的代码优雅而实用,可惜纯粹从速度上来看它比大多数语言都要慢。大多数人也认为的速度和易于使用是两极对立的——编写C代码的确非常痛苦。而 Cython 试图消除这种两重性,并让你同时拥有 Python 的语法和 C 数据类型和函数——它们两个都是世界上最好的。请记住,我绝不是我在这方面的专家,这是我的第一次Cython真实体验的笔记:
编辑:根据一些我收到的反馈,大家似乎有点混淆——Cython是用来生成 C 扩展到而不是独立的程序的。所有的加速都是针对一个已经存在的 Python 应用的一个函数进行的。没有使用C 或 Lisp 重写整个应用程序,也没有手写C扩展 。只是用一个简单的方法来整合C的速度和C数据类型到 Python 函数中去。
现在可以说,我们能使下文的great_circle 函数更快。所谓great_circle 是计算沿地球表面两点之间的距离的问题:
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改写它,然后看看是否有差别:
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
请注意,我们仍然importmath——cython让您在一定程度上混搭Python和C数据类型在。转换是自动的,但并非没有代价。在这个例子中我们所做的就是定义一个Python函数,声明它的输入参数是浮点数类型,并为所有变量声明类型为C浮点数据类型。计算部分它仍然使用了Python的 math 模块。
现在我们需要将其转换为C代码再编译为Python扩展。完成这一部的最好的办法是编写一个名为setup.py发布脚本。但是,现在我们用手工方式 ,以了解其中的巫术:
<pre name="code" class="plain"># 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</pre>
现在你应该有一个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), "sec"
约1.8秒 。并没有我们一开始期望的那种大大的性能提升。使用 python 的 math 模块应该是瓶颈。现在让我们使用C标准库替代之:
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*c
与 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函数的话,我们也许能够加快速度。
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 <math .h>
#include <stdio .h>
#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 -octest ctest.c编译它,测试用time./ctest ...大约0.2秒 。这使我有信心,我Cython扩展相对于我的C代码也极有效率(这并不是说我的C编程能力很弱)。
能够用 cython 优化多少性能通常取决于有多少循环,数字运算和Python函数调用,这些都会让程序变慢。已经有一些人报告说在某些案例上 100 至 1000 倍的速度提升。至于其他的任务,可能不会那么有用。在疯狂地用 Cython重写 Python 代码之前,记住这一点:
"我们应该忘记小的效率,过早的优化是一切罪恶的根源,有 97% 的案例如此。"——DonaldKnuth
换句话说,先用 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入门.VS.C++的更多相关文章
- Cython入门Demo(Linux)
众所周知,Python语言是非常简单易用的,但是python程序在运行速度上还是有一些缺陷.于是,Cython就应运而生了,Cython作为Python的C扩展,保留了Python的语法特点,集成C语 ...
- 【原创】cython and python for kenlm
未经允许不可转载 Kenlm相关知识 Kenlm下载地址 kenlm中文版本训练语言模型 如何使用kenlm训练出来的模型C++版本 关于Kenlm模块的使用及C++源码说明 加载Kenlm模块命令 ...
- Windows下Cython使用(VS2017)
收到公众号推送文章“利用Cython为Python代码加速”后尝试在Windows平台下使用Cython,环境为Python3.5 + VS2017. 1. 简单尝试 1)新建hello.pyx文件, ...
- Pthon学习相关
1. Cython入门教程:https://www.jianshu.com/p/cfcc2c04a6f5
- Cython: 快速入门
1. Cython是什么? 它是一个用来快速生成Python扩展模块(extention module)的工具,语法是Python和c的混血.在Cython,C里的类型,如int,float,long ...
- cython教程
.写测试代码: zhouhh@zhouhh-home:~$ vi test.pyx [python] view plaincopy def sayhello(char* str): if str == ...
- 【转】python入门指引
http://matrix.42qu.com/10757179 前言 其实我也不知道python怎么入门,由我来写这个真的不是很合适.我学python是直接找了dive into python来看.然 ...
- PyTorch进行深度学习入门
一.PyTorch是什么? 这是一个基于Python的科学计算软件包,针对两组受众: ①.NumPy的替代品,可以使用GPU的强大功能 ②.深入学习研究平台,提供最大的灵活性和速度 二.入门 ①.张量 ...
- SaltStack 入门到精通第二篇:Salt-master配置文件详解
SaltStack 入门到精通第二篇:Salt-master配置文件详解 转自(coocla):http://blog.coocla.org/301.html 原本想要重新翻译salt-mas ...
随机推荐
- 绝对好用的浏览器json解析网址
你们是否经常在浏览器输入请求地址解析遇到中文乱码的情况,今天我找到了一个好用的浏览器解析json网址,绝对好用. 1.直接输入网址 http://pro.jsonlint.com/ 2.输入要解析的j ...
- 洛谷P1307 数字反转【水题】
给定一个整数,请将该数各个位上数字反转得到一个新数.新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零(参见样例2). 输入输出格式 输入格式: 一个整数 NN ...
- 爬虫系列(二) Chrome抓包分析
在这篇文章中,我们将尝试使用直观的网页分析工具(Chrome 开发者工具)对网页进行抓包分析,更加深入的了解网络爬虫的本质与内涵 1.测试环境 浏览器:Chrome 浏览器 浏览器版本:67.0.33 ...
- 运行npm run watch时报:events.js:182 throw er; // Unhandled 'error' event
I had this issue i did the following steps and i have no issues anymore: Delete node_modules directo ...
- RONOJ——PID204 / 特种部队 ☆
题目描述 某特种部队接到一个任务,需要潜入一个仓库.该部队士兵分为两路,第一路士兵已经在正面 牵制住了敌人,第二路士兵正在悄悄地从后方秘密潜入敌人的仓库. 当他们到达仓库时候,发现这个仓库的锁是一把很 ...
- magento 的一些关于addFieldToFilter的查询
1,匹配country_id的首字母,查询国家,返回数组 //查询国家数据集 $countryCollection=Mage::getResourceModel('directory/country_ ...
- nutch的定时增量爬取
译文来着: http://wiki.apache.org/nutch/Crawl 介绍(Introduction) 注意:脚本中没有直接使用Nutch的爬去命令(bin/nutch crawl或者是& ...
- POJ 2914
无向图全局最小割算法 求 G=(V, E)中任意 s-t 最小割的算法: 定义w(A, x) = ∑w(v[i], x),v[i] A ∈ 定义 Ax 为在x 前加入 A 的所有点的集合(不包括 ...
- hive正則表達式
hive中实现正則表達式,与java中的正則表達式有所差别: 这里经过探索总结了一些: hive中的正则能够用,可是有所差别,差别在于原来的'\' 转义,这里变成了双斜杠了'\\' hive中的正则解 ...
- matlab实现基于DFS的Ford_Fulkerson最大流最小割算法
function [F, maxf, V, S] = Ford_Fulkerson(C, src, sink) n = size(C, 1); F = zeros(n); maxf = 0; V = ...