我在Cython工作。我怎样才能声明一个python类实例的C数组,然后将数组传递给python函数并对其进行处理?
cdef int n=100
class particle:
def __init__(self):
self.x=uniform(1,99)
self.y=uniform(1,99)
self.pot=0
cdef particle parlist[n]
def CalPot(parlist[]):
for i in range(N-1):
pot=0
for j in range(i,N):
dx=parlist[j].x-parlist[i].x
dy=parlist[j].y-parlist[j].y
r2=dx**2+dy**2
pot=pot+4*ep*r2*((sig/r2)**12 - (sig/r2)**6)
parlist[i].pot=pot
答案 0 :(得分:0)
Python类的实例是Python对象,在Python中处理得更好(它们不是C类型,我没有看到在Cython源代码中为它们创建某种形式的C表示的任何理由)。此外,更好地避免使用n
和parlist
等全局变量(在此示例中,它们不是必需的)。
class particle:
def __init__(self):
self.x = uniform(1, 99)
self.y = uniform(1, 99)
self.pot = 0
def CalPot(parlist):
N = len(parlist)
for i in range(N):
pot = 0
for j in range(i, N):
dx = parlist[j].x - parlist[i].x
dy = parlist[j].y - parlist[j].y
r2 = dx**2 + dy**2
pot = pot + 4 * ep * r2 * ((sig / r2)**12 - (sig / r2)**6)
parlist[i].pot = pot
所以这个Cython代码恰好是纯Python。
答案 1 :(得分:0)
正如Ioannis和DavidW告诉你的那样,你不应该创建一个python对象的c数组,而应该使用python列表。
对产生的纯Python进行Cyton化会带来大约2倍的速度,因为cython会删除解释器部分。但是,如果你还要摆脱引用计数和动态调度,那么还有更多的潜力 - 速度提升到100倍是很常见的。前段时间我回答a question说明了这一点。
你应该怎样做才能加快速度?你需要用"裸金属"替换python-multiplication。乘法。
第一步:不要为particle
使用(python)类,使用简单的c-struct - 它只是一个数据集合 - 仅此而已:
cdef struct particle:
double x
double y
double pot
第一个好处:可以定义这些结构的全局c数组(另一个问题是,在一个更大的项目中是否非常聪明):
DEF n=2000 # known at compile time
cdef particle parlist[n]
在数组初始化之后(有关详细信息,请参阅附件列表),我们可以在calcpot
- 函数中使用它(我略微更改了您的定义):
def calcpot():
cdef double pot,dX,dY
cdef int i,j
for i in range(n):
pot=0.0
for j in range(i+1, n):
dX=parlist[i].x-parlist[j].x
dY=parlist[i].y-parlist[j].y
pot=pot+1.0/(dX*dX+dY*dY)
parlist[i].pot=pot
与原始代码的主要区别:parlist[i].x
和Co.不再是慢速python对象,而是简单快速的doubles
。为了能够获得最大的加速速度,需要考虑许多微妙的事情 - 一个人应该阅读/重读cython documentation。
麻烦值得吗?我的机器上有时间(通过%timeit calcpot()
):
Time Speed-up
pure python + interpreter: 924 ms ± 14.1 ms x1.0
pure python + cython: 609 ms ± 6.83 ms x1.5
cython version: 4.1 ms ± 55.3 µs x231.0
使用低姿势加速231
!
列出python代码:
import random
class particle:
def __init__(self):
self.x=random.uniform(1,99)
self.y=random.uniform(1,99)
self.pot=0
n=2000
parlist = [particle() for _ in range(n)]
def calcpot():
for i in range(n):
pot=0.0
for j in range(i+1, n):
dX=parlist[i].x-parlist[j].x
dY=parlist[i].y-parlist[j].y
pot=pot+1.0/(dX*dX+dY*dY)
parlist[i].pot=pot
列出cython代码:
#call init_parlist prior to calcpot!
cdef struct particle:
double x
double y
double pot
DEF n=2000 # known at compile time
cdef particle parlist[n]
import random
def init_parlist():
for i in range(n):
parlist[i].x=random.uniform(1,99)
parlist[i].y=random.uniform(1,99)
parlist[i].pot=0.0
def calcpot():
cdef double pot,dX,dY
cdef int i,j
for i in range(n):
pot=0.0
for j in range(i+1, n):
dX=parlist[i].x-parlist[j].x
dY=parlist[i].y-parlist[j].y
pot=pot+1.0/(dX*dX+dY*dY)
parlist[i].pot=pot