借助Cython编写C代码
借助Cython编写C代码,在过去两年,我使用Cython来完成大部分的工作。当然我并不是指先编写Python的代码,然后再通过各种类型声明等来“Cythonize”化。我是直接编写Cython代码,使用”原生“的C数据结构和数组,偶尔也有C++的容器,借助于我自己编写的一个malloc/free的装饰函数。编写的代码能达到C/C++的性能,因为它本质上就是C/C++的代码,只不过加了些Python中的语法糖。
这基本上不再遵循Python语言所遵守的旧规则:你将会使用Python语言来编写整个项目,但是针对其中的”热点“问题使用C语言进行优化,得到的结果就是同时拥有C的性能和Python的便捷性,而且非常可靠。
通常,理论比实践会更加优美。在实际过程中,你的数据结果会很大地影响到代码的性能,以及编写的难易性。数组虽然痛苦但比较快,而列表比较便捷,但是比较慢。Python的循环和函数调用也比较慢,所以你应该将这部分代码用C语言来编写。
今天在HN上有一篇文章,作者同时编写了纯粹的Python实现和C实现,使用NumpyCAPI。这看起来是展示二者不同的好机会,所以我编写了一个Cython的实现以作对比:
importrandom
fromcymem.cymemcimportPool
fromlibc.mathcimportsqrt
cimportcython
cdefstructPoint:
doublex
doubley
cdefclassWorld:
cdefPoolmem
cdefintN
cdefdouble*m
cdefPoint*r
cdefPoint*v
cdefPoint*F
cdefreadonlydoubledt
def__init__(self,N,threads=1,m_min=1,m_max=30.0,r_max=50.0,v_max=4.0,dt=1e-3):
self.mem=Pool()
self.N=N
self.m=<double*>self.mem.alloc(N,sizeof(double))
self.r=<Point*>self.mem.alloc(N,sizeof(Point))
self.v=<Point*>self.mem.alloc(N,sizeof(Point))
self.F=<Point*>self.mem.alloc(N,sizeof(Point))
foriinrange(N):
self.m[i]=random.uniform(m_min,m_max)
self.r[i].x=random.uniform(-r_max,r_max)
self.r[i].y=random.uniform(-r_max,r_max)
self.v[i].x=random.uniform(-v_max,v_max)
self.v[i].y=random.uniform(-v_max,v_max)
self.F[i].x=0
self.F[i].y=0
self.dt=dt
@cython.cdivision(True)
defcompute_F(Worldw):
"""Computetheforceoneachbodyintheworld,w."""
cdefinti,j
cdefdoubles3,tmp
cdefPoints
cdefPointF
foriinrange(w.N):
#Setallforcestozero.
w.F[i].x=0
w.F[i].y=0
forjinrange(i+1,w.N):
s.x=w.r[j].x-w.r[i].x
s.y=w.r[j].y-w.r[i].y
s3=sqrt(s.x*s.x+s.y*s.y)
s3*=s3*s3;
tmp=w.m[i]*w.m[j]/s3
F.x=tmp*s.x
F.y=tmp*s.y
w.F[i].x+=F.x
w.F[i].y+=F.y
w.F[j].x-=F.x
w.F[j].y-=F.y
@cython.cdivision(True)
defevolve(Worldw,intsteps):
"""Evolvetheworld,w,throughthegivennumberofsteps."""
cdefint_,i
for_inrange(steps):
compute_F(w)
foriinrange(w.N):
w.v[i].x+=w.F[i].x*w.dt/w.m[i]
w.v[i].y+=w.F[i].y*w.dt/w.m[i]
w.r[i].x+=w.v[i].x*w.dt
w.r[i].y+=w.v[i].y*w.dt
Cython的代码花费了大概30分钟来编写,而且它运行的速度和C代码一样快。因为它本质上就是C代码,只不过加了一些语法糖而已,甚至你不需要学习或了解外部的复杂的CAPI,你只需要编写C或C++代码。Cython和C版本的代码都比纯粹的Python版本快了大概70倍,它们都使用了Numpy数组。
和C语言的不同之处在于:关于malloc/free我编写了一段装饰代码——cymem,它的作用就是记录它所占用的地址,当垃圾回收器工作时,它会释放掉分配的内存空间。目前为止,我还没有遇到过内存泄漏的问题。
另一种编写Cython的方式就是借助于使用Numpy多维度的数组特性,然而这对我来说更加复杂了,而且我所尝试解决的问题很少会涉及数组问题,所以我都会使用自己定义的数据结构。
Python培训、Python培训班、Python培训机构,就选光环大数据!
还不够过瘾?想学习更多?点击 http://hadoop.aura.cn/python/ 进行Python学习!
大数据培训、人工智能培训、Python培训、大数据培训机构、大数据培训班、数据分析培训、大数据可视化培训,就选光环大数据!光环大数据,聘请专业的大数据领域知名讲师,确保教学的整体质量与教学水准。讲师团及时掌握时代潮流技术,将前沿技能融入教学中,确保学生所学知识顺应时代所需。通过深入浅出、通俗易懂的教学方式,指导学生更快的掌握技能知识,成就上万个高薪就业学子。 更多问题咨询,欢迎点击------>>>>在线客服!